home *** CD-ROM | disk | FTP | other *** search
/ Windows News 2010 Summer - Disc 1 / WN_Ete2010_CD1.iso / Onglet5 / Weezo / Weezo setup.exe / {code_appDir} / www / includes / commonFunctions.php < prev    next >
PHP Script  |  2010-05-19  |  216KB  |  5,358 lines

  1. <?php
  2. /**
  3.  * Common functions used by scripts
  4.  *
  5.  * Add several "all purpose" functions used by resource scripts
  6.  * - read / write general/user/resource variables
  7.  * - files access rights
  8.  * - log/debug
  9.  * - data exchange with main application
  10.  * - misc...
  11.  *
  12.  * PHP version 5
  13.  *
  14.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  15.  * that is available through the world-wide-web at the following URI:
  16.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  17.  * the PHP License and are unable to obtain it through the web, please
  18.  * send a note to license@php.net so we can mail you a copy immediately.
  19.  *
  20.  * @category   NA
  21.  * @package    NA
  22.  * @author     Nicolas Bruley / Peer 2 World <contact@weezo.net>
  23.  * @copyright  2005-2008 Nicolas Bruley / Peer 2 World
  24.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  25.  * @version    CVS: $Id:$
  26.  * @link       http://www.weezo.net
  27.  * @since      File available since Release 1.0.0
  28.  */
  29.  
  30.  
  31. define('LOG_NON',-1);     /** Information */
  32. define('LOG_INF',0);     /** Information */
  33. define('LOG_DET',1);     /** Detailed information */
  34. define('LOG_ER',3);     /** Error */
  35. define('LOG_DBG',3);     /** Debug information */
  36.  
  37. // Defines max time (ms) a script may lock a session. Above that time, old script looses its rights over the session
  38. // Used to prevent a hanged script blocks whole session
  39. define("SESSION_MAX_LOCK_TIME",5000);
  40.  
  41. define("TRANSFERS_REFRESH","10");
  42. define("ADRESS_MAXLENGHT","60");
  43. define("DEFAULT_JPG_QUALITY",70);
  44. define("DEFAULT_RESIZE_METHOD",2);
  45. define("IMAGE_COMMENTS_EDIT_COLS",'53');
  46. define("IMAGE_COMMENTS_EDIT_ROWS",'4');
  47. define("IMAGE_COMMENTS_EDIT_HEIGHT",'75');
  48. define("DEFAULT_SLIDESHOW_INTERVAL",'4');
  49.  
  50. define('APPLICATION_NAME','Weezo');
  51. define("DOWNLOAD_SITE","http://download.weezo.net");
  52. define("APP_SITE","http://www.weezo.net");
  53. define("DNS_SITE","http://weezo.net");
  54.  
  55. define("FILE_CONTACTS", '/contacts.txt');
  56. define("FILE_UPLOADS", '/data/uploads.txt');
  57. define("FILE_TRANSFERS", '/data/transfers.txt');
  58. define("FILE_GENERAL", '/data/general.ini');
  59.  
  60. define("WMP_MOBILE_AUDIO_EXT",'.convert.asf');
  61. define("WMP_MOBILE_VIDEO_EXT",'.convert.wmv');
  62.  
  63. define('EVENT_CONNECTION',0);
  64.  define('S_EVENT_LOGIN',1);
  65.  define('S_EVENT_LOGOUT',2);
  66. define('EVENT_SERVERSTATE',1);
  67.  define('S_EVENT_OFF',1);
  68.  define('S_EVENT_LAN',2);
  69.  define('S_EVENT_WEB',3);
  70. define('EVENT_RESOURCEACCESS',2);
  71.  
  72.  
  73.  
  74. /**
  75.  ***************************************************************************************************************************
  76.  * In-Memory data functions  (In-memory data is data shared between all scripts)
  77.  ***************************************************************************************************************************
  78.  */
  79.  
  80. /**
  81.  * @desc set In-memory data
  82.  *
  83.  * @param string $key : data name
  84.  * @param mixed $value : data value
  85.  */
  86. function cfMSetVar($key,$value,$raw=false){
  87.     customSetData($key,(($raw)?$value:serialize($value)));
  88. }
  89. /**
  90.  * @desc get In-memory data value
  91.  *
  92.  * @param string $key : data name
  93.  * @return mixed $value : data value
  94.  */
  95. function cfMGetVar($key=false,$raw=false){
  96.     if($key===false) {
  97.         $r=array();
  98.         foreach (customGetData('') as $key=>$value) $r[$key]=unserialize($value);
  99.         return $r;
  100.     }
  101.     if($raw) return customGetData($key);
  102.     return @unserialize(customGetData($key));
  103. }
  104. /**
  105.  * @desc check if In-memory data is set
  106.  *
  107.  * @param string $key : data name
  108.  * @return  boolean : true if data is set, false if not set
  109.  */
  110. function cfMIssetVar($key){
  111.     //if(file_exists(cfAppDataDir().'/temp/temp_'.$key)) return true; else return false;
  112.     return customIssetData($key);
  113. }
  114. /**
  115.  * @desc unset if In-memory data
  116.  *
  117.  * @param string $key : data name
  118.  */
  119. function cfMUnsetVar($key){
  120.     //if(file_exists(cfAppDataDir().'/temp/temp_'.$key)) unlink(cfAppDataDir().'/temp/temp_'.$key);
  121.     customUnsetData($key);
  122. }
  123. /**
  124.  * @desc Return an array of all memory data names
  125.  *
  126.  * @return array(dataName=>dataName)
  127.  */
  128. function cfMGetVarList(){return customGetDataList();}
  129.  
  130.  
  131. /**
  132.  ***************************************************************************************************************************
  133.  * PHP Session replacement
  134.  ***************************************************************************************************************************
  135.  */
  136. function wSession_save_path(){return dirname(session_save_path());}
  137. function wSession_start($readOnly=false){
  138.     $_SESSION=false;
  139.     // If session-less request, set readOnly to false
  140.     if(isset($_GET['noSession'])) $readOnly=false;
  141.  
  142.     // If session is already opened, abort
  143.     if(@$_ENV['wSession']['state']==='opened') return;
  144.  
  145.     // Get id from wSession_id then from cookie, and restore session
  146.     $id=(isset($_ENV['wSession']['id']))?$_ENV['wSession']['id']:((isset($_COOKIE['WSESSID']))?$_COOKIE['WSESSID']:0);
  147.  
  148.     if($id){
  149.         // Wait until session is not locked by any other process
  150.         $nb=0; while((!$readOnly) && cfMIssetVar('wSessionLocked_'.$id) && ($nb++<SESSION_MAX_LOCK_TIME)) usleep(1000);
  151.         // Re-lock session
  152.         if(!$readOnly) cfMSetVar('wSessionLocked_'.$id,$_ENV['requestID']);
  153.         // Get session data from session file
  154.         $_SESSION=@unserialize(@file_get_contents(wSession_save_path().'/sess_'.$id));
  155.  
  156.         // XSRF protection: if user is logged and referer doesn't match with this site, exit
  157.         if(isset($_SESSION['userLogged']) && ($headers=getallheaders()) && isset($headers['Referer'])) {
  158.             $refererURL=parse_url($headers['Referer']);
  159.  
  160.             $host=$_SERVER['HTTP_HOST']; if(strpos($host,':')) $host=substr($host,0,strpos($host,':'));
  161.  
  162.             // If referer differs from actual host, reject
  163.             if(isset($refererURL['host']) && $refererURL['host']!==$host){
  164.                 // Except if it commes from weezo.net (remove all POST & GET data in this case)
  165.                 if($refererURL['host']=='weezo.net'){
  166.                     $_GET=array();
  167.                     $_POST=array();
  168.                 }
  169.                 else{
  170.                     cfMUnsetVar('wSessionLocked_'.$id);
  171.                     die('Unauthorized access: '.$headers['Referer'].' != '.$_SERVER['HTTP_HOST'].' ('.$host.')');
  172.                 }
  173.             }
  174.         }
  175.     }
  176.  
  177.     if(!$_SESSION){
  178.         if(isset($_ENV['wSession']['id'])) $id=$_ENV['wSession']['id'];
  179.         else {
  180.             $id=''; for ($i=0;$i<26;$i++) $id.=chr(rand(0,255));
  181.             $id=substr(str_replace(array('/','=','+'),'',base64_encode($id)),0,22);
  182.         }
  183.         if(!$readOnly) cfMSetVar('wSessionLocked_'.$id,$_ENV['requestID']);
  184.         $_SESSION=array();
  185.     }
  186.     if($id&&!$readOnly) setcookie('WSESSID',$id,null,'/');
  187.  
  188.     $_ENV['wSession']=array('id'=>$id,'state'=>(($readOnly)?'closed':'opened'));
  189.     register_shutdown_function('wSession_write_close');
  190. }
  191. function wSession_start_nowrite(){wSession_start(true);}
  192. function wSession_id($newId=false){
  193.     if($newId) $_ENV['wSession']['id']=$newId;
  194.     return (string)@$_ENV['wSession']['id'];
  195. }
  196. function wSession_destroy(){
  197.     $id=wSession_id();
  198.     if(substr($id,0,3)=='UI_') return ;
  199.     @unlink(wSession_save_path().'/sess_'.$id);
  200.     cfMUnsetVar('wSessionLocked_'.$id);
  201.     @setcookie('WSESSID',null,time()-3600,'/');
  202.     $_ENV['wSession']['state']='destroyed';
  203. }
  204. function wSession_write_close($commitToFile=true){
  205.     if(@$_ENV['wSession']['state']!='opened') return;
  206.     $id=$_ENV['wSession']['id'];
  207.     if(isset($_ENV['wSessionBeforeWriteClose'])) call_user_func($_ENV['wSessionBeforeWriteClose']);
  208.  
  209.     // Check that request has actually opened and locked session before saving if not, discard changes
  210.     if($commitToFile && cfMGetVar('wSessionLocked_'.$id)==$_ENV['requestID'])
  211.         file_put_contents(wSession_save_path().'/sess_'.$id,serialize($_SESSION));
  212.     $_ENV['wSession']['state']='closed';
  213.     cfMUnsetVar('wSessionLocked_'.$id);
  214. }
  215. /**
  216.  * @desc Set a function to be called before closing session (so far used only for cfSetSavedRVarC()
  217.  *
  218.  * @param string $function: function name
  219.  */
  220. function wSession_setBeforeWriteClose($function){$_ENV['wSessionBeforeWriteClose']=$function;}
  221.  
  222.  
  223. /*
  224.  ***************************************************************************************************************************
  225.  * Genera/User/Resource data management,
  226.  * Special directories management
  227.  ***************************************************************************************************************************
  228.  */
  229.  
  230. /**
  231.  * @return true if non-existent directory or successfully unlinked directory, else if dir couldn't be unlinked
  232.  * @desc unlink logged user temporary data directory (if exists)
  233. */
  234. function cfAppUserTempDirUnlink() {
  235.     $userTempDir=cfAppDataDir()."/sessiondata/".wSession_id();
  236.     if(file_exists($userTempDir)) return cfUnlinkDir($userTempDir); else return true;
  237. }
  238.  
  239. /**
  240.  * @return mixed required data
  241.  * @param string $dataName name of data
  242.  * @param string $notFound : (optional) returned value when not found * @param string $notFound : (optional) returned value when not found
  243.  * @desc return data named $dataName, red in general.ini file,
  244.  *             and stored in $_SESSION['weezoGeneral'] array (1st) or $_ENV['weezoGeneral'] (if not in session)
  245. */
  246. function cfGGetVar($dataName=false,$subDataName=false, $notFound=false){
  247.     //@$_ENV['call'][$dataName]++;
  248.     if(!$dataName) return (array)@$_ENV['weezoGeneral']+(array)@$_SESSION['weezoGeneral'];
  249.     if    ($subDataName===false && isset($_SESSION['weezoGeneral'][$dataName])) $data=$_SESSION['weezoGeneral'][$dataName];
  250.     elseif($subDataName!==false && isset($_SESSION['weezoGeneral'][$dataName][$subDataName])) $data=$_SESSION['weezoGeneral'][$dataName][$subDataName];
  251.     elseif($subDataName===false && isset($_ENV['weezoGeneral'][$dataName])) $data=$_ENV['weezoGeneral'][$dataName];
  252.     elseif($subDataName!==false && isset($_ENV['weezoGeneral'][$dataName][$subDataName])) $data=$_ENV['weezoGeneral'][$dataName][$subDataName];
  253.     else return $notFound;
  254.     if(!is_array($data) && strtolower($data)=='false') return false;
  255.     if(!is_array($data) && strtolower($data)=='true') return true;
  256.     return $data;
  257. }
  258. /**
  259.  * @return true
  260.  * @param string $dataName
  261.  * @param mixed $value
  262.  * @param bool $save: true to update in-memory value
  263.  * @desc put $value in general data named $dataName : $_SESSION['weezoGeneral'][$dataName]=$value
  264. */
  265. function cfGSetVar($dataName,$value,$save=false){
  266.     if($save) cfMSetVar('weezoGeneral',array($dataName=>$value)+cfMGetVar('weezoGeneral'));
  267.     $_SESSION['weezoGeneral'][$dataName]=$value;
  268.     return true;
  269. }
  270. /**
  271.  * @param string $dataName
  272.  * @desc unset a general var (user defined only, not common vars)
  273. */
  274. function cfGUnsetVar($dataName){unset($_SESSION['weezoGeneral'][$dataName]);}
  275. /**
  276.  * @desc Update G value in session and into UI
  277.  *
  278.  * @param string $dataName
  279.  * @param mixed $value
  280.  * @param mixed $immediateCommit:
  281.  *             true to request app to save to general.ini on reception, false to update on app, 'serverOnly' to update only on server
  282.  */
  283. function cfGUpdateVar($dataName,$value,$immediateCommit=false){
  284.     // Retreive current memory data
  285.     $mem=cfMGetVar('weezoGeneral');
  286.     // If no change, do nothing
  287.     if($value===@$mem[$dataName]) return ;
  288.     // Update for this session (in $_SESSION)
  289.     cfGSetVar($dataName,$value,true);
  290.     // Update in memory
  291.     $mem[$dataName]=$value; cfMSetVar('weezoGeneral',$mem);
  292.  
  293.     // If immediate commit to app
  294.     if($immediateCommit!=='serverOnly'){
  295.         $args=array('name'=>$dataName,'value'=>$value);
  296.         if(!$immediateCommit) $args+=array('noCommit'=>1);
  297.         cfServerSendCmd('changeParameter',$args); // Apply to app
  298.     }
  299. }
  300.  
  301. /**
  302.  * @desc Reload G vars from in-memory array (used for long-lasting scripts such as bittorrent seeder)
  303.  *
  304.  */
  305. function cfGReloadVars(){$_ENV['weezoGeneral']=cfMGetVar('weezoGeneral');}
  306.  
  307. /**
  308.  * @return mixed required data
  309.  * @param string $dataName name of data
  310.  * @param string $notFound : (optional) returned value when not found
  311.  * @desc return user data named $dataName, red in user .usr file, and stored in $_SESSION['user'] array
  312. */
  313. function cfUGetVar($dataName=false,$notFound=false){
  314.     if(@$_ENV['weezoSession']['user']) {
  315.         if($dataName) return @$_ENV['weezoSession']['user'][$dataName];
  316.         return @$_ENV['weezoSession']['user'];
  317.     }
  318.     if($dataName===false) return $_SESSION['user'];
  319.     if (isset($_SESSION['user'][$dataName])) return $_SESSION['user'][$dataName];
  320.     return $notFound;
  321. }
  322. /**
  323.  * @return true
  324.  * @param string $dataName
  325.  * @param mixed $value
  326.  * @desc put $value in current user data named $dataName : $_SESSION['user'][$dataName]=$value
  327. */
  328. function cfUSetVar($dataName,$value){
  329.     $_SESSION['user'][$dataName]=$value;
  330.     return true;
  331. }
  332.  
  333. /**
  334.  * @desc Create a fake resource context so cfRGetVar / cfRSetVar functions can be used out of resource context
  335.  *         (User Interface, administration...)
  336.  *
  337.  */
  338. function cfRCreateFakeResource(){
  339.     $_SESSION['activeResourceId']='foo';
  340.     $_SESSION['res']['foo']['id']='fooId';
  341. }
  342. /**
  343.  * @return true if var set, false if var couldn't be set (because array specified by $arg1 [,$arg2]... doesn't exist)
  344.  * @param string $arg1
  345.  * @param string $arg2
  346.  * @param string $arg3
  347.  * @param string $arg4
  348.  * @desc Set resource level var
  349.  *         Using this function to store resource session variable ensure there will be no collision with variables used by other resources
  350.  *         var is stored in $_SESSION['res'][active resource id] array and sub arrays
  351.  *         if only $arg1 and $arg2 are passed, then store $arg2 value in $_SESSION['res'][active resource id][$arg1]
  352.  *         if only $arg3 is provided, then store $arg3 value in $_SESSION['res'][active resource id][$arg1][$arg2]
  353.  *         if $arg4 is provided, then store $arg4 value in $_SESSION['res'][active resource id][$arg1][$arg2][$arg4]
  354. */
  355. function cfRSetVar($arg1, $arg2, $arg3='_Parameter_not_set_', $arg4='_Parameter_not_set_',$resourceId=false){
  356.     if($resourceId===false) $resourceId=$_SESSION['activeResourceId'];
  357.     if(!isset($_SESSION['res'][$resourceId])) $_SESSION['res'][$resourceId]=array();
  358.     if(!($arg4==='_Parameter_not_set_')){
  359.         if(!isset($_SESSION['res'][$resourceId][$arg1])) $_SESSION['res'][$resourceId][$arg1]=array();
  360.         if(!isset($_SESSION['res'][$resourceId][$arg1][$arg2])) $_SESSION['res'][$resourceId][$arg1][$arg2]=array();
  361.         $_SESSION['res'][$resourceId][$arg1][$arg2][$arg3]=$arg4; return true;
  362.     }
  363.     if(!($arg3==='_Parameter_not_set_')){
  364.         if(!isset($_SESSION['res'][$resourceId][$arg1])) $_SESSION['res'][$resourceId][$arg1]=array();
  365.         $_SESSION['res'][$resourceId][$arg1][$arg2]=$arg3; return true;
  366.     }
  367.     $_SESSION['res'][$resourceId][$arg1]=$arg2; return true;
  368. }
  369. /**
  370.  * @desc Return var defined for current resource
  371.  *        if only arg1 is passed, return var named "arg1" ($_SESSION['res'][$currentResource][$arg1]
  372.  *         if arg1 and arg2 are passed, return "arg2" index from "arg1" array ($_SESSION['res'][$currentResource][$arg1][$arg2] (use cfRSetVarArray to define array)
  373.  *         if arg1, arg2 and arg3 are passed, return "arg3" index from "arg1" / "arg2" array ($_SESSION['res'][$currentResource][$arg1][$arg2][$arg3] (use cfRSetVarArray to define array)
  374.  * @param string $arg1 : var or array name
  375.  * @param string $arg2 : (optional) var or array name
  376.  * @param string $arg3 : (optional) var name
  377.  * @param string $notFound : (optional) returned value when not found
  378.  * @return mixed value
  379. */
  380. function &cfRGetVar($arg1=false, $arg2=false, $arg3=false, $notFound=false){
  381.     static $memCached=false;
  382.     static $resourceId=false;
  383.  
  384.     // If session not started or no active resource, return false
  385.     $false=$notFound;
  386.     if(!isset($_SESSION) || !isset($_SESSION['activeResourceId'])) {
  387.         // Workaround to allow cfRGetVar in extensions using genuine PHP sessions
  388.         if(isset($_ENV['weezoSession']['activeResourceId'])){
  389.             $resourceId=0;
  390.             $_SESSION['res'][0]=$_ENV['weezoSession']['res'][$_ENV['weezoSession']['activeResourceId']];
  391.         }
  392.         else return $false;
  393.     }
  394.     else{
  395.         // If resource id changed, reset cache
  396.         if($resourceId!==$_SESSION['activeResourceId']) $memCached=false;
  397.         $resourceId=$_SESSION['activeResourceId'];
  398.     }
  399.  
  400.     // Load resource unmodified data
  401.     if(!$memCached) {
  402.         if(!isset($_SESSION['res'][$resourceId]['id'])) return $false;
  403.         $memCached=cfMGetVar('weezoResData'.$_SESSION['res'][$resourceId]['id']);
  404.     }
  405.  
  406.     // return requested data
  407.     if($arg1===false){ // All data (debug or rcInitLimitedConfig)
  408.         $tmp=$_SESSION['res'][$resourceId]+$memCached;
  409.          return $tmp;
  410.     }
  411.     if($arg3!==false){
  412.         if(isset($_SESSION['res'][$resourceId][$arg1][$arg2][$arg3])) return $_SESSION['res'][$resourceId][$arg1][$arg2][$arg3];
  413.         if(isset($memCached[$arg1][$arg2][$arg3])) return $memCached[$arg1][$arg2][$arg3];
  414.     }
  415.     elseif($arg2!==false){
  416.         if(isset($_SESSION['res'][$resourceId][$arg1][$arg2])) return $_SESSION['res'][$resourceId][$arg1][$arg2];
  417.         if(isset($memCached[$arg1][$arg2])) return $memCached[$arg1][$arg2];
  418.     }
  419.     else {
  420.         if(isset($_SESSION['res'][$resourceId][$arg1])) return $_SESSION['res'][$resourceId][$arg1];
  421.         if(isset($memCached[$arg1])) return $memCached[$arg1];
  422.     }
  423.     return $false;
  424. }
  425. /**
  426.  * @desc Return true if variable is set (see cfRGetVar for args)
  427.  * @return boolean
  428.  */
  429. function cfRIssetVar($arg1,$arg2=false,$arg3=false){
  430.     return (cfRGetVar($arg1,$arg2,$arg3,null)===null)?false:true;
  431. }
  432. /**
  433.  * @return true if OK, false if array cannot be creates
  434.  * @param string $arg1 : array name
  435.  * @param string $arg2 : (optional) 2nd level array name
  436.  * @desc set an array bound to current resource ($_SESSION['res'][$currentResource][$arg1] or $_SESSION['res'][$currentResource][$arg1][$arg2])
  437. */
  438. function cfRSetVarArray($arg1, $arg2=false, $resourceId=false){
  439.     if($resourceId===false) $resourceId=$_SESSION['activeResourceId'];
  440.     if($arg2!==false){
  441.         if(!isset($_SESSION['res'][$resourceId][$arg1])) return false;
  442.         $_SESSION['res'][$resourceId][$arg1][$arg2]=array(); return true;
  443.     }
  444.     $_SESSION['res'][$resourceId][$arg1]=array(); return true;
  445. }
  446. /**
  447.  * @return true if success
  448.  * @param Name of array or 1st level of array $arg1
  449.  * @param optional: 2nd level of array $arg2
  450.  * @param optional: 3rd level of array $arg3
  451.  * @desc unset a variable / array of resource level data ($_SESSION['res']
  452. */
  453. function cfRUnsetVar($arg1, $arg2=false, $arg3=false){
  454.     if($arg3!==false) unset($_SESSION['res'][$_SESSION['activeResourceId']][$arg1][$arg2][$arg3]);
  455.     if($arg2!==false) unset($_SESSION['res'][$_SESSION['activeResourceId']][$arg1][$arg2]);
  456.     else unset($_SESSION['res'][$_SESSION['activeResourceId']][$arg1]);
  457.     return true;
  458. }
  459. /**
  460.  * @desc Initialize r var if not already set
  461.  *
  462.  * @param string $varName
  463.  * @param mixed $value
  464.  */
  465. function cfRInitVar($varName,$defaultValue,$allowedValues=false){
  466.     if(cfRGetVar($varName,false,false,null)===null || ($allowedValues && !in_array(cfRGetVar($varName),$allowedValues))) cfRSetVar($varName,$defaultValue);
  467. }
  468.  
  469.  
  470. /**
  471.  * @desc return an array of all connected-user's resources
  472.  *
  473.  * @return array(nonUniqueId=>data)
  474.  */
  475. function cfResourcesGetUser(){
  476.     $resources=array();
  477.     foreach ($_SESSION['res'] as $id=>$res) if(isset($res['id'])) $resources[$id]=$res+cfMGetVar('weezoResData'.$res['id']);
  478.     return $resources;
  479. }
  480.  
  481. /**
  482.  * @desc Return an array of all defined resources (user independant)
  483.  *
  484.  * @return array(resourceUniqueID=>resourceData)
  485.  */
  486. function cfResourcesGetAll(){
  487.     foreach (cfMGetVar('weezoResourcesList') as $id=>$filename)    $resources[$id]=cfMGetVar('weezoResData'.$id);
  488.     return $resources;
  489. }
  490.  
  491. /**
  492.  * @desc set (context-appliable) theme-level data
  493.  *
  494.  * @param string $dataName: name of variable
  495.  * @param string $value: value
  496.  */
  497. function cfTSetVar($dataName,$value){
  498.     $themes=cfMGetVar('weezoThemes');
  499.     $themes[cfActualTheme()][$dataName]=$value;
  500.     cfTGetVar(false,'reset'); // Reset theme data
  501. }
  502. /**
  503.  * @desc return (context-appliable) theme-level data
  504.  *
  505.  * @param srting $dataName: name of variable
  506.  * @param string $notFound : (optional) returned value when not found
  507.  * @return mixed value
  508.  */
  509. function cfTGetVar($dataName=false, $notFound=false){
  510.     static $themes;
  511.     if($notFound=='reset') {$themes=false;return;}// Reset theme data
  512.     if(!$themes) $themes=cfMGetVar('weezoThemes');
  513.     if(!$dataName) return $themes[cfActualTheme()];
  514.     if(isset($themes[cfActualTheme()][$dataName])) return $themes[cfActualTheme()][$dataName];
  515.     return $notFound;
  516. }
  517. /**
  518.  * @desc "Heritable" variable :
  519.  *             seek for variable at resource-level, then user-level, then general-level, and if not found, use $defaultValue
  520.  *
  521.  * @param string $dataName : name of variable
  522.  * @param mixed $defaultValue : value if not defined at resource / user / general levels
  523.  * @return mixed : value
  524.  */
  525. function cfHGetVar($dataName, $defaultValue=false){
  526.     if(cfIsResource() && ($ret=cfRGetVar($dataName,false,false,null))!==null) return $ret;
  527.     if(($ret=cfUGetVar($dataName,null))!==null) return $ret;
  528.     if(($ret=cfGGetVar($dataName,false,null))!==null) return $ret;
  529.     return $defaultValue;
  530. }
  531. /**
  532.  * @desc "Heritable" variable, inverted order (general-level highest priority) :
  533.  *             seek for variable at general-level, then user-level, then resource-level, and if not found, use $defaultValue
  534.  *
  535.  * @param string $dataName : name of variable
  536.  * @param mixed $defaultValue : value if not defined at resource / user / general levels
  537.  * @return mixed : value
  538.  */
  539. function cfHiGetVar($dataName, $defaultValue=false){
  540.     if(($ret=cfGGetVar($dataName,false,null))!==null) return $ret;
  541.     if(($ret=cfUGetVar($dataName,null))!==null) return $ret;
  542.     if(cfIsResource() && ($ret=cfRGetVar($dataName,false,false,null))!==null) return $ret;
  543.     return $defaultValue;
  544. }
  545. /**
  546.  * @desc get browser capability
  547.  *
  548.  * @param string $dataName
  549.  */
  550. function cfBGetVar($dataName=false){
  551.     static $cache;
  552.     if(cfIsInApp() && !cfGGetVar('browserCaps')) cfSetBrowserCaps();
  553.     if(!isset($cache)) $cache=array();
  554.     if(!$dataName) return cfGGetVar('browserCaps');
  555.     if(!isset($cache[$dataName])) $cache[$dataName]=cfGGetVar('browserCaps',$dataName);
  556.     return $cache[$dataName];
  557. }
  558.  
  559. /**
  560.  * Close current session to perform long tasks, before restarting it with cfSessionRestart
  561.  *
  562.  */
  563. function cfSessionPause(){
  564.     $_ENV['activeResourceId']=@$_SESSION['activeResourceId'];
  565.     wSession_write_close();
  566. }
  567. /**
  568.  * Restart session paused by cfSessionPause
  569.  *
  570.  */
  571. function cfSessionRestart(){
  572.     wSession_start();
  573.     $_SESSION['activeResourceId']=$_ENV['activeResourceId'];
  574. }
  575. /**
  576.  * @desc Detect if a session is started and not write_closed (i.e. locked)
  577.  *
  578.  * @return boolean
  579.  */
  580. function cfSessionIsStarted(){
  581.     if(!wSession_id()) return false;
  582.     if(!file_exists(cfAppDataDir().'/sessiondata/sess_'.wSession_id())) return false;
  583.     return customFileSize(cfAppDataDir().'/sessiondata/sess_'.wSession_id())==8589934591;
  584. }
  585.  
  586. /**
  587.  * @return string
  588.  * @desc returns application root directory
  589. */
  590. function cfAppRootDir() {return str_replace('\\','/',substr(ini_get('extension_dir'),0,strlen(ini_get('extension_dir'))-8));}
  591. /**
  592.  * @return string application data root directory (= application root directory for compact installations,
  593.  *             or CSIDL_APPDATA/weezo for Vista-like installs
  594.  *             data root directory includes www, data and shared directories
  595.  * @desc returns application data root directory
  596. */
  597. function cfAppDataRootDir() {
  598.     if($_SERVER['DOCUMENT_ROOT']) return substr($_SERVER['DOCUMENT_ROOT'],0,strlen($_SERVER['DOCUMENT_ROOT'])-4);
  599.     return str_replace('\\','/',substr(__FILE__,0,strlen(__FILE__)-33));
  600. }
  601. /**
  602.  * @return string
  603.  * @desc returns application bin (executables) directory
  604. */
  605. function cfAppBinDir() {return cfAppRootDir().'/bin';}
  606. /**
  607.  * @return string
  608.  * @desc returns application bin (executables) directory
  609. */
  610. function cfAppServerDir() {return cfAppRootDir().'/apache';}
  611. /**
  612.  * @return string
  613.  * @desc returns application data directory
  614. */
  615. function cfAppDataDir() {return cfAppDataRootDir().'/data';}
  616. /**
  617.  * @return string
  618.  * @desc returns logs directory
  619. */
  620. function cfAppLogDir() {return cfAppDataDir().'/log';}
  621. /**
  622.  * @return string application data directory
  623.  * @desc returns application data directory
  624. */
  625. function cfAppTempDir() {return cfAppDataRootDir().'/data/temp';}
  626. /**
  627.  * @return string document root (www) directory
  628.  * @desc returns document root (www) directory
  629. */
  630. function cfAppDocRoot() {return cfAppDataRootDir().'/www';}
  631. /**
  632.  * @return string default shared directory
  633.  * @desc returns default shared directory
  634. */
  635. function cfAppSharedDir() {return cfAppDataRootDir().'/shared';}
  636. /**
  637.  * @return string theme directory
  638.  * @param boolean $docRootRelative : set to true to return path from doc root
  639.  * @desc returns theme directory
  640. */
  641. function cfAppThemeDir($docRootRelative=false){
  642.     if($docRootRelative) return cfTGetVar('path'); else return cfTGetVar('dir');
  643. }
  644. /**
  645.  * @desc return actually applied theme
  646.  *
  647.  * @return strin : theme name
  648.  */
  649. function cfActualTheme(){
  650.     // if launched from weezo UI, load application skin theme
  651.     // if resource theme exists, load it else
  652.     // if user theme exists, load it else
  653.     // if general test exists, load it, else
  654.     // load default theme
  655.  
  656.     // Use cached value first
  657.     if(isset($_ENV['weezo']['actualTheme'])) return $_ENV['weezo']['actualTheme'];
  658.  
  659.     if(cfIsInApp()) return 'skins/default';
  660.     elseif(cfBGetVar('theme')) $_ENV['weezo']['actualTheme']=cfBGetVar('theme');
  661.     elseif(substr($_SERVER['PHP_SELF'],0,5)=='/res/' && isset($_SESSION['activeResourceId']) && cfRGetVar('theme') && file_exists(cfAppDocRoot().'/themes/'.cfRGetVar('theme').'/theme.css') && $_SERVER['PHP_SELF']!='/menuFrame.php' && $_SERVER['PHP_SELF']!='/mainFrame.php') $_ENV['weezo']['actualTheme']=cfRGetVar('theme');
  662.     elseif(cfUGetVar('theme') && file_exists(cfAppDocRoot().'/themes/'.cfUGetVar('theme').'/theme.css')) $_ENV['weezo']['actualTheme']=cfUGetVar('theme');
  663.     elseif(cfGGetVar('theme') && file_exists(cfAppDocRoot().'/themes/'.cfGGetVar('theme').'/theme.css')) $_ENV['weezo']['actualTheme']=cfGGetVar('theme');
  664.     else $_ENV['weezo']['actualTheme']='simple';
  665.     return $_ENV['weezo']['actualTheme'];
  666. }
  667. /**
  668.  * @return string directory
  669.  * @param bool $createIfDoesntExist if set to true, create temp directory in non-existant
  670.  * @desc returns logged user temporary data directory (located in /data/sessiondata)
  671.           temporary data directory name is session id
  672.           this dir should be used to store private stuff (out of apache document root) specific to an user (temp images...)
  673. */
  674. function cfAppUserTempDir($createIfDoesntExist=true) {
  675.     static $userTempDir;
  676.     if(isset($userTempDir)) return $userTempDir;
  677.  
  678.     $userTempDir=cfAppDataDir()."/sessiondata/".wSession_id();
  679.     if(!file_exists($userTempDir)){
  680.         if($createIfDoesntExist && (!mkdir($userTempDir))) $userTempDir=false;
  681.         if(!$createIfDoesntExist) $userTempDir=false;
  682.     }
  683.     return $userTempDir;
  684. }
  685.  
  686.  
  687. /**
  688.  * @return string directory
  689.  * @desc returns current resource directory (located in /data/res/"resourceType"/"resourceSubType"/"resourceName")
  690.           this dir should be used to store private stuff (out of apache document root) specific to a resource (temp images...)
  691.           if dir doesn't exist, try to create it
  692. */
  693. function cfAppResourceDir($resourceId=false) {
  694.     static $return;
  695.     // Use/set cache
  696.     if(isset($return[$resourceId])) return $return[$resourceId];
  697.     $return[$resourceId]=cfRGetVar('resourceDataDir',false,false,$resourceId);
  698.  
  699.     // Try to create resource directory if needed
  700.     if(!is_dir($return[$resourceId])) @mkdir($return[$resourceId]);
  701.     return $return[$resourceId];
  702. }
  703. /**
  704.  * @desc return relative path from resource base path (cfRGetVar('path'))
  705.  *         returned path is formed like : "*resourceBasePath* /relativePath"
  706.  *
  707.  * @param string $absolutePath: path to processs
  708.  * @param boolean $skipResourceBasePath: true to include *resourceBasePath* / , false not to.
  709.  */
  710. function cfResourceRelativePath($absolutePath, $skipResourceBasePath=false){
  711.     if(cfSharedMode()==='list'){
  712.         if(cfCmpLeft($absolutePath,'*resourceBasePath*')) return (($skipResourceBasePath)?substr($absolutePath,18):$absolutePath);
  713.         foreach (cfRGetVar('sharedItems') as $cfn=>$type) {
  714.             if($cfn==$absolutePath) return(($skipResourceBasePath)?'':'*resourceBasePath*').'/'.basename($cfn);
  715.             if($type=='d' && cfIsSubDir($cfn,$absolutePath)){
  716.                 $cfn=dirname($cfn);
  717.                 if($skipResourceBasePath) return substr($absolutePath,strlen($cfn)+1);
  718.                 return cfJoinPathFile('*resourceBasePath*',substr($absolutePath,strlen($cfn)));
  719.             }
  720.         }
  721.         return false;
  722.     }
  723.     if($absolutePath=='*resSpecific*') return $absolutePath;
  724.     if(!cfIsSubDir(cfRGetVar('path'),$absolutePath)) return false;
  725.     if(cfRGetVar('path')=='computerRoot') return $absolutePath;
  726.     if($skipResourceBasePath) return substr($absolutePath,strlen(cfRGetVar('path'))+1);
  727.     return '*resourceBasePath*'.substr($absolutePath,strlen(cfRGetVar('path')));
  728. }
  729. /**
  730.  * @desc return relative path from resource base path (cfAppDataDir())
  731.  *         returned path is formed like : "*resourceBasePath* /relativePath"
  732.  *
  733.  * @param string $absolutePath
  734.  */
  735. function cfResourceDataDirRelativePath($absolutePath){
  736.     if(!cfIsSubDir(cfAppDataDir(),$absolutePath)) return false;
  737.     return '*resourceDataDirBasePath*'.substr($absolutePath,strlen(cfAppResourceDir()));
  738. }
  739. /**
  740.  * @return boolean result of check
  741.  * @param string $path
  742.  * @desc Check if $path is a path or subpath of one of the general protected dirs array
  743. */
  744. function cfIsGeneralProtected($path,$protectedDirArray=false){
  745.     static $cache;
  746.  
  747.     $path=strtolower(cfCleanPathName($path));
  748.     if(!is_array($protectedDirArray)){
  749.         if(!isset($cache)) $cache=cfGGetVar('protectedDirs');
  750.         foreach ($cache as $protDir) {if (cfIsSubDir($protDir, $path)) return true;}
  751.     }
  752.     else{
  753.         foreach ($protectedDirArray as $protDir) {if (cfIsSubDir($protDir, $path)) return true;}
  754.     }
  755.     return false;
  756. }
  757. /**
  758.  * @return unknown
  759.  * @param string $path
  760.  * @desc Check if $path includes a path of one of the general protected dirs array
  761. */
  762. function cfIncludesGeneralProtectedDir($path){
  763.     static $protectedDirs;
  764.     if(!isset($protectedDirs)) $protectedDirs=cfGGetVar('protectedDirs');
  765.  
  766.     $path=strtolower(cfCleanPathName($path));
  767.     foreach ($protectedDirs as $protDir) {if (cfIsSubDir($path,$protDir)) return true;}
  768.     return false;
  769. }
  770. /**
  771.  * @return mixed array of file or dir 's rights or string right of selected item
  772.  *            'state' : synthetic result : 'out of resource path', 'invalid', 'authorized', 'protected'
  773.              'read' : read files and subdirs authorisation (dir only)
  774.              'download' : download authorisation (file or dir)
  775.              'write' : write authorisation (dir only)
  776.              'modify' : modify/overwrite authorisation (file or dir)
  777.              'search' : search authorisation (dir) (not yet implemented)
  778.              'execute'  serverside execute authorisation (file only)
  779.              'upload' : upload authorisation (dir only)
  780.              'remoteDownload' : remoteDownload authorisation (dir only)
  781.              'send' : send authorisation through P2P app (dir or file)
  782.  * @param string $completeFilename : name of dir or file
  783.  * @param string $item : right to check ('read', 'download'...), leave to false to retrieve full rights array;
  784.  * @param boolean $unsafeDir: set to false to indicate than file or folder's directory is clean and allowed, set to true to perform full check
  785.  * @param boolean $itemInSubDir: used only for "list" sharedMode with $unsafeDir=true: true to indicate that item is in a subdir, false if item is directly within shared items
  786.  * @desc Return an array of given file or dir rights. If $item is provided, only right corresponding to item is returned,
  787. */
  788. function cfFileRights($completeFilename, $item=false, $unsafeDir=true, $itemInSubDir=NULL){
  789.     static $cache;
  790.  
  791.     // Cache function main data
  792.     if(!isset($cache)){
  793.         $cache=array();
  794.  
  795.         // Resource specific file rights functions : create function
  796.         if(cfRGetVar('fileRightsFunction')) $cache['fileRightsFunction'] = create_function('$completeFilename,$item,$unsafeDir', cfRGetVar('fileRightsFunction'));
  797.         else $cache['fileRightsFunction'] = false;
  798.  
  799.         $cache['path']=cfRGetVar('path');
  800.         $cache['subFoldersIncluded']=cfRGetVar('subFoldersIncluded');
  801.         $cache['sharedMode']=cfSharedMode();
  802.         $cache['protectedFilesExtensions']= array_flip(array_merge(
  803.             explode(',',cfRGetVar('protectedFilesExtensions')),    explode(',',cfGGetVar('protectedFilesExtensions'))));
  804.             unset($cache['protectedFilesExtensions']['']);
  805.  
  806.         $cache['downloadAllowed']=((cfGGetVar('generalDownloadProtection'))?false:cfRGetVar('downloadAllowed'));
  807.         $cache['writeAllowed']=((cfGGetVar('generalWriteProtection'))?false:cfRGetVar('writeAllowed'));
  808.         $cache['modifyAllowed']=((cfGGetVar('generalModifyProtection'))?false:cfRGetVar('modifyAllowed'));
  809.         $cache['executeAllowed']=((cfGGetVar('generalExecuteProtection'))?false:cfRGetVar('executeAllowed'));
  810.  
  811.         $cache['searchAllowed']=cfHiGetVar('searchAllowed',false);
  812.         $cache['remoteDownloadAllowed']=cfHiGetVar('remoteDownloadAllowed',false);
  813.         $cache['uploadAllowed']=cfHiGetVar('uploadAllowed',true);
  814.         $cache['sendAllowed']=cfHiGetVar('sendAllowed',false);
  815.         $cache['userTempDirAccessAllowed']=cfRGetVar('userTempDirAccessAllowed');
  816.         $cache['resourceDataDirAccessAllowed']=cfRGetVar('resourceDataDirAccessAllowed');
  817.         $cache['resourceDataDir']=cfRGetVar('resourceDataDir');
  818.         $cache['protectSensitiveFiles']=cfHiGetVar('protectSensitiveFiles');
  819.         $cache['sharedItems']=cfRGetVar('sharedItems');
  820.  
  821.         if(cfGGetVar('generalShowHiddenFiles')=='all' || (cfGGetVar('generalShowHiddenFiles')=='admin' && cfUGetVar('administrator'))) $cache['showHiddenFiles']=true; else $cache['showHiddenFiles']=false;
  822.         if(cfGGetVar('generalShowSystemFiles')=='all' || (cfGGetVar('generalShowSystemFiles')=='admin' && cfUGetVar('administrator'))) $cache['showSystemFiles']=true; else $cache['showSystemFiles']=false;
  823.         if(cfGGetVar('generalAllowReadOnlyFilesOverwrite')=='all' || (cfGGetVar('generalAllowReadOnlyFilesOverwrite')=='admin' && cfUGetVar('administrator'))) $cache['protectReadOnly']=false; else $cache['protectReadOnly']=true;
  824.     }
  825.     // Init rights
  826.     $rights=array('state'=>'authorized', 'read'=>false, 'download'=>false, 'write'=>false, 'modify'=>false, 'search'=>false, 'execute'=>false, 'upload'=>false, 'remoteDownload'=>false, 'send'=>false);
  827.  
  828.     // Hide weezoAccess files
  829.     if(basename($completeFilename)=='weezoAccess.txt') {
  830.         $rights['state']='protected';
  831.         if($item) return $rights[$item]; else return $rights;
  832.     }
  833.  
  834.     // corrects c:/.. or c:.. complete file names
  835.     if(substr($completeFilename,-4)==':/..' || substr($completeFilename,-3)==':..') $completeFilename='computerRoot';
  836.  
  837.     // computer root specific rights
  838.     if($completeFilename=='computerRoot'){
  839.         // Return resource specific file rights
  840.         if($cache['fileRightsFunction']) {
  841.                 if(($fileRightsFunctionResult=$cache['fileRightsFunction']($completeFilename, $item, $unsafeDir))!==null) return $fileRightsFunctionResult;
  842.         }
  843.  
  844.         if($cache['path']=='computerRoot') {
  845.             $rights['read']=true;
  846.             if($cache['searchAllowed']) $rights['search']=true;
  847.         }
  848.         else $rights['state']='out of resource path';
  849.         if($item) return $rights[$item]; else return $rights;
  850.     }
  851.  
  852.     // Clean file name. if $completeFilename doesn't exist, exit
  853.     if(!$completeFilename || ($unsafeDir && !($completeFilename=cfCleanPathName($completeFilename)))){
  854.         $rights['state']='invalid'; if($item) return $rights[$item]; else return $rights;
  855.     }
  856.     if(is_dir($completeFilename)){$isdir=true; $dir=$completeFilename;}
  857.     else{$isdir=false;$dir=(cfDirname($completeFilename));if(strlen($dir)==3 && substr($dir,1)==':/') $dir=substr($dir,0,2);}
  858.  
  859.     // As userDir is a subdir of installation directory (which is a protected dir), access rights are granted through 'userTempDirAccessAllowed' resource data
  860.     // If userTempDirAccessAllowed is set to true, user may read/write data located in his temp dir (data/sessionData/"session ID"), (no modify...)
  861.     if($unsafeDir || $isdir){
  862.         if($cache['userTempDirAccessAllowed'] && cfIsSubDir(cfAppUserTempDir(false),$completeFilename)){// if user may access his temp dir
  863.             if($isdir) {$rights['read']=true; $rights['write']=true; return $rights;}
  864.             if(!$isdir) {$rights['read']=true; $rights['download']=true; return $rights;}
  865.         }
  866.     }
  867.     // as resource Dir is a subdir of installation directory (which is a protected dir), access rights are granted through 'resourceDataDirAccessAllowed' resource data
  868.     // if resourceDataDirAccessAllowed is set to true, user may read data located in resource datadir (data/sessionData/"session ID"), (no modify...)
  869.     if($cache['resourceDataDirAccessAllowed'] && cfIsSubDir($cache['resourceDataDir'],$completeFilename)){// if user may access resource data dir
  870.         if($isdir) {$rights['read']=true;  return $rights;}
  871.         if(!$isdir) {$rights['read']=true; $rights['download']=true; return $rights;}
  872.     }
  873.  
  874.     // Resource specific file rights functions
  875.     if($cache['fileRightsFunction']) {
  876.         //if file belongs to general protectedDir[] (or is a subdir of a general protectedDir) or has a protected extension
  877.         if(cfIsGeneralProtected($completeFilename) || ($cache['protectSensitiveFiles'] && isset($cache['protectedFilesExtensions'][cfFileExtension($completeFilename)]))) {
  878.             $rights['state']='protected';  if($item) return $rights[$item]; else return $rights; //$file protected : exit
  879.         }
  880.         // Return resource specific file rights
  881.         if(($fileRightsFunctionResult=$cache['fileRightsFunction']($completeFilename, $item, $unsafeDir))!==null) return $fileRightsFunctionResult;
  882.  
  883.     }
  884.  
  885.     // Check folder rights
  886.     if($unsafeDir || $isdir){
  887.         if(cfIsGeneralProtected($completeFilename)) {//if file belongs to general protectedDir[] (or is a subdir of a general protectedDir)
  888.             $rights['state']='protected';  if($item) return $rights[$item]; else return $rights; //$file protected : exit
  889.         }
  890.     }
  891.     // If unsafe dir, verify that file/folder is contained into an authorized folder
  892.     if($unsafeDir){
  893.         if($cache['sharedMode']=='list'){
  894.             // 1st look in sharedItems list
  895.             foreach ($cache['sharedItems'] as $cfn=>$type) if($cfn==$completeFilename) $rights['state']='authorized';
  896.             // If not OK, look in subdirectories
  897.             if($rights['state']!='authorized'){
  898.                 foreach ($cache['sharedItems'] as $cfn=>$type) if($type=='d' && cfIsSubDir($cfn,$completeFilename)){
  899.                     // Apply upper directory rights
  900.                     $rights['state']=cfFileRights($dir,'state',true);
  901.                 }
  902.             }
  903.         }
  904.         else{
  905.             $resourcePath=strtolower($cache['path']);
  906.             // if not directly in path folder
  907.             if(strtolower($dir)!=$resourcePath){
  908.                 if(!$cache['subFoldersIncluded'])  $rights['state']='out of resource path';
  909.                 else {
  910.                     if($cache['path']!='computerRoot'){
  911.                         if(substr(strtolower($dir),0,strlen($resourcePath))==$resourcePath){
  912.                             if(substr(strtolower($dir),strlen($resourcePath),1) && substr(strtolower($dir),strlen($resourcePath),1)!='/' && substr(strtolower($dir),strlen($resourcePath),1)=='\\') $rights['state']='out of resource path';
  913.                         }
  914.                         else $rights['state']='out of resource path';
  915.                     }
  916.                     // Check that all upper directories are authorized
  917.                     if($rights['state']=='authorized' && strlen($dir)>3){
  918.                         $rights['state']=cfFileRights(dirname($dir),'state',true);
  919.                     }
  920.                 }
  921.             }
  922.         }
  923.         if($rights['state']!='authorized') {if($item) return $rights[$item]; else return $rights;} //$file out of resource path : exit
  924.     }
  925.     // safe dir but file directly in sharedItems: check that it's one of those items
  926.     elseif ($itemInSubDir===false){
  927.         if(cfSharedMode('list')){
  928.             $found=false;
  929.             foreach ($cache['sharedItems'] as $cfn=>$type) if($cfn==$completeFilename) $found=true;
  930.             if(!$found) {
  931.                 $rights['state']='invalid';
  932.                 if($item) return $rights[$item]; else return $rights;
  933.             }
  934.         }
  935.     }
  936.     // $itemInSubDir hint not passed, search in whole items list
  937.     elseif ($itemInSubDir===NULL && cfSharedMode('list')){
  938.         $found=false;
  939.         foreach ($cache['sharedItems'] as $cfn=>$type) if($cfn==$completeFilename) $found=true;
  940.         if(!$found) {
  941.             foreach ($cache['sharedItems'] as $cfn=>$type) if($type=='d' && cfIsSubDir($cfn,$completeFilename)) $found=true;
  942.             if(!$found) {
  943.                 $rights['state']='invalid';
  944.                 if($item) return $rights[$item]; else return $rights;
  945.             }
  946.         }
  947.     }
  948.  
  949.     // Get "HSR" file attirbutes
  950.     if($completeFilename=='*resourceBasePath*') $fileAttr='   '; else $fileAttr=customFileAttributes($completeFilename);
  951.  
  952.     // If system or hidden
  953.     if((!$cache['showHiddenFiles'] && $fileAttr[0]=='H') || (!$cache['showSystemFiles'] && $fileAttr[1]=='S')){
  954.         $rights['state']='invalid';
  955.         if($item) return $rights[$item]; else return $rights;
  956.     };
  957.  
  958.     // if belongs to protected file types
  959.     if(!$isdir && $cache['protectSensitiveFiles'] && isset($cache['protectedFilesExtensions'][cfFileExtension($completeFilename)])) {
  960.         $rights['state']='protected';
  961.         if($item) return $rights[$item]; else return $rights;
  962.     }
  963.     // Check that folder access is not forbidden by a weezoAccess file
  964.     elseif ($isdir && file_exists($completeFilename.'/weezoAccess.txt')) {
  965.         $weezoAccess=file_get_contents($completeFilename.'/weezoAccess.txt')."\n";
  966.         if(preg_match('/exclude(\s)*=(\s)*('.cfUGetVar('name').'|all)(\s)*\n/',$weezoAccess)){
  967.             $rights['state']='protected';
  968.             if($item) return $rights[$item]; else return $rights;
  969.         }
  970.     }
  971.     if($item=='state') return $rights[$item];
  972.  
  973.     // GET OTHER FILE/FOLDER RIGHTS
  974.     $sharedListBaseDir=($completeFilename=='*resourceBasePath*' && $cache['sharedMode']);
  975.  
  976.     // dir and file view right
  977.     $rights['read']=true;
  978.  
  979.     // file download right
  980.     if($cache['downloadAllowed']) $rights['download']=true;
  981.  
  982.     // Read-only files or dir
  983.     if($cache['protectReadOnly'] && $fileAttr[2]=="R"){
  984.         $rights['write']=false;
  985.         $rights['modifyAllowed']=false;
  986.     }
  987.     else{
  988.         // dir write (of files inside dir) right
  989.         if($cache['writeAllowed'] && $isdir && !$sharedListBaseDir) $rights['write']=true;
  990.  
  991.         // dir or file modify right
  992.         if($cache['modifyAllowed'] && ($rights['write'] || !$isdir)) $rights['modify']=true;
  993.     }
  994.     // dir search right
  995.     if($cache['searchAllowed'] && $isdir && !$cache['sharedMode']) $rights['search']=true;
  996.  
  997.     // file execute right
  998.     if($cache['executeAllowed'] && !$isdir) $rights['execute']=true;
  999.  
  1000.     // dir upload (of files inside dir) right
  1001.     if($cache['uploadAllowed'] && $isdir && !$sharedListBaseDir) $rights['upload']=true;
  1002.  
  1003.     // dir direct download (of files inside dir) right
  1004.     if($cache['remoteDownloadAllowed'] && $isdir && !$sharedListBaseDir) $rights['remoteDownload']=true;
  1005.  
  1006.     //if $dir includes a protected dir, modify some of access rights:
  1007.     if($isdir && cfIncludesGeneralProtectedDir($dir)){$rights['modify']=false;}
  1008.     if($item) return $rights[$item]; else return $rights; // return result
  1009. }
  1010.  
  1011. /**
  1012.  * @desc return sharedMode
  1013.  * @param $string isMode: if set, return true if this mode is set
  1014.  * @return string: "list" or "folder" or boolean if $isMode supplied
  1015.  */
  1016. function cfSharedMode($isMode=false){return (($isMode)?cfRGetVar('sharedMode')===$isMode:cfRGetVar('sharedMode'));}
  1017.  
  1018. /**
  1019.  * @desc return array of shared items
  1020.  * @return array(cfn=>"d" (dir) or "f" (file))
  1021.  */
  1022. function cfSharedItems(){return cfRGetVar('sharedItems');}
  1023.  
  1024. /**
  1025.  * @desc Convert a *resourceBasePath* /path or file into actual filename
  1026.  *
  1027.  * @param string $protectedFilename
  1028.  * @return string: actual filename, false if not in shared items
  1029.  */
  1030. function cfSharedCompleteFilename($protectedFilename){
  1031.     if(!cfCmpLeft($protectedFilename,'*resourceBasePath*/')) return false;
  1032.     $f=substr($protectedFilename,19);
  1033.  
  1034.     if(substr($f,-3)=='/..'){
  1035.         $f=cfStrShorten($f,3);
  1036.         $f=substr($f,0,strrpos($f,'/'));
  1037.     }
  1038.     if(!$f) return '*resourceBasePath*';
  1039.  
  1040.  
  1041.     // in subdir
  1042.     if(strpos($f,'/')!==false){
  1043.         $dirName=substr($f,0,strpos($f,'/'));
  1044.         foreach (cfRGetVar('sharedItems') as $cfn=>$type) if($type=='d' && basename($cfn)==$dirName) {
  1045.             return $cfn.substr($f,strpos($f,'/'));
  1046.         }
  1047.         return false;
  1048.     }
  1049.  
  1050.     // In items
  1051.     foreach (cfRGetVar('sharedItems') as $cfn=>$type){
  1052.         if(basename($cfn)==$f) return $cfn;
  1053.     }
  1054.     return false;
  1055. }
  1056.  
  1057.  
  1058.  
  1059. /**
  1060.  * @desc Grant / remove access right to a given directory inside document root through htaccess
  1061.  *
  1062.  * @param string $path : doc root relative path, or false to remove session's all granted access (with action set to 'remove')
  1063.  * @param string $action : 'add' or  'remove'
  1064.  * @return true if success, false if failed
  1065.  */
  1066. function cfHtaccessGrant($path, $action='add'){
  1067.     $htaccessGranted=cfUGetVar('htaccessGranted');
  1068.  
  1069.     // Remove all granted access for session
  1070.     if(!$path && $action=='remove' && is_array($htaccessGranted)){
  1071.         foreach ($htaccessGranted as $path => $foo) cfHtaccessGrant($path,$action);
  1072.         cfUSetVar('htaccessGranted',false);
  1073.     }
  1074.     if(!$path) return true;
  1075.     if(!is_dir(cfAppDocRoot().$path)) return false;
  1076.  
  1077.     // Read .htaccess file
  1078.     $access=array();
  1079.     if(file_exists(cfAppDocRoot().$path.'/.htaccess') && $fp=fopen(cfAppDocRoot().$path.'/.htaccess','r')){
  1080.         while (!feof($fp)){
  1081.             $line=fgets($fp,1024);
  1082.             if(substr($line,0,1)=='#' && strpos($line,'=')){
  1083.                 $line=explode('=',trim(substr($line,1)),2);
  1084.                 if(count($line)==2) $access[$line[0]]=$line[1];
  1085.             }
  1086.         }
  1087.         fclose($fp);
  1088.     }
  1089.  
  1090.     // Remove inexistant sessions and and current session if requested
  1091.     foreach ($access as $sess=>$ip) if(!file_exists(cfAppDataDir().'/sessiondata/sess_'.$sess) || $sess==wSession_id()) unset($access[$sess]);
  1092.     if($action=='remove' && isset($htaccessGranted[$path])) unset($htaccessGranted[$path]);
  1093.  
  1094.     // Add current session if requested
  1095.     if($action=='add') {
  1096.         $access[wSession_id()]=$_SERVER['REMOTE_ADDR'];
  1097.         $htaccessGranted[$path]=1;
  1098.     }
  1099.  
  1100.     // Write htaccess file
  1101.     @unlink(cfAppDocRoot().$path.'/.htaccess');
  1102.     if(count($access)){
  1103.         $htaccess='';
  1104.         foreach ($access as $session => $ip) $htaccess.="# ".$session.'='.$ip."\n";
  1105.         $htaccess.="<LIMIT GET POST>\n";
  1106.         $htaccess.="Order deny,allow\nAllow from";
  1107.         foreach ($access as $ip) $htaccess.=' '.$ip;
  1108.         $htaccess.="\nDeny from all\n";
  1109.         $htaccess.="</LIMIT>";
  1110.         file_put_contents(cfAppDocRoot().$path.'/.htaccess',$htaccess);
  1111.     }
  1112.  
  1113.     cfUSetVar('htaccessGranted',$htaccessGranted);
  1114.     return true;
  1115. }
  1116.  
  1117. /**
  1118.  * @desc Check wether direct connections from out-of-LAN, without passing through centralized authentication are allowed
  1119.  *
  1120.  * @return boolean
  1121.  */
  1122. function cfDirectWebConnectionsAllowed(){
  1123.     return !(($regData=cfIsRegistered()) && isset($regData['externalAuth']) && $regData['externalAuth'] && isset($regData['directWebConnectionsAllowed']) && !$regData['directWebConnectionsAllowed']);
  1124. }
  1125.  
  1126. /*
  1127.  ***************************************************************************************************************************
  1128.  * I/O Functions
  1129.  ***************************************************************************************************************************
  1130.  */
  1131.  
  1132. /**
  1133.  * @return string $cleanString
  1134.  * @param string $string : string to clean
  1135.  * @desc transform < and > signs into their HTML equivalent. if $keepBasicHTMLformat, keep <b>, <u>...
  1136. */
  1137. function cfHTMLSafeString($string, $keepBasicHTMLformat=true){
  1138.     $cleanString=htmlspecialchars($string);
  1139.     if($keepBasicHTMLformat){
  1140.         $cleanString=str_replace('<b>','<b>',$cleanString);
  1141.         $cleanString=str_replace('</b>','</b>',$cleanString);
  1142.         $cleanString=str_replace('<u>','<u>',$cleanString);
  1143.         $cleanString=str_replace('</u>','</u>',$cleanString);
  1144.         $cleanString=str_replace('<i>','<i>',$cleanString);
  1145.         $cleanString=str_replace('</i>','</i>',$cleanString);
  1146.         $cleanString=str_replace('<h1>','<h1>',$cleanString);
  1147.         $cleanString=str_replace('</h1>','</h1>',$cleanString);
  1148.         $cleanString=str_replace('<h2>','<h2>',$cleanString);
  1149.         $cleanString=str_replace('</h2>','</h2>',$cleanString);
  1150.         $cleanString=str_replace('<h3>','<h3>',$cleanString);
  1151.         $cleanString=str_replace('</h3>','</h3>',$cleanString);
  1152.         $cleanString=str_replace('<br />','<br/>',$cleanString);
  1153.         $cleanString=str_replace('<br/>','<br/>',$cleanString);
  1154.         $cleanString=str_replace('<br>','<br/>',$cleanString);
  1155.         $cleanString=str_replace("\r",'<br />',str_replace("\n",'<br />',str_replace("\r\n",'<br />',$cleanString)));
  1156.     }
  1157.     return $cleanString;
  1158. }
  1159.  
  1160. /**
  1161.  * @return string : encoded string
  1162.  * @param string $string : string to encode
  1163.  * @desc Encode a string into an XML compatible format (replace "&" by & and < by "<"
  1164. */
  1165. function cfXMLEncode($string){return str_replace('<','<',str_replace('&','&',$string));}
  1166. function cfXMLEncodeProperty($string){return str_replace('<','<',str_replace('&','&',str_replace('"','"',$string)));}
  1167.  
  1168. /**
  1169.  * @return string utf-8 encoded string
  1170.  * @param string $string : string to encode
  1171.  * @param bool $check : if true, verify that $string is not already utf-8 encoded
  1172.  * @param bool $protectAmp : if true, protect amp char
  1173.  * @desc Encode an $_ENV['weezoLng']['_CHARSET_'] encoded string into utf-8 encoded string.
  1174. */
  1175. function cfUTF8Encode($string, $check=false, $protectAmp=true){
  1176.     static $encoding=0;
  1177.     if($protectAmp) $string=str_replace('&', '&',$string);
  1178.     if(!$encoding) $encoding=cfMGetVar('systemCodepage');
  1179.     if($check) {if(@iconv($encoding,'UTF-8',@iconv('UTF-8',$encoding,$string))==$string) return $string;}
  1180.     return @iconv($encoding,'UTF-8',$string);
  1181. }
  1182.  
  1183. /**
  1184.  * @return string $_ENV['weezoLng']['_CHARSET_'] encoded string
  1185.  * @param string $string : string to encode
  1186.  * @param bool $utf8Decode : true if string must be utf-8 decoded : default true
  1187.  * @param bool $stripSlashes : true if string must be stripslashed : default true
  1188.  * @param bool $cleanHTML : remove HTML tags (except basic ones (<br>, <b>...)) : default true
  1189.  * @param integer $truncate : max len of string (0 means unlimited), default 8196
  1190. * @desc Process an UTF-8 encoded user typed string : default action : strip slashes, remove HTML tags (except basic ones (<br>, <b>...))
  1191. */
  1192. function cfUTF8Decode($string, $utf8Decode=true, $stripSlashes=true, $cleanHTML=true, $truncate=8196){
  1193.     static $encoding=0;
  1194.     if(!$encoding) $encoding=cfMGetVar('systemCodepage');
  1195.     $string=str_replace('&','&',$string);
  1196.     if($stripSlashes) $string=(stripcslashes($string));
  1197.     if($cleanHTML) $string=cfHTMLSafeString($string);
  1198.     if($utf8Decode) $string=@iconv('UTF-8',$encoding,$string);
  1199.     if($truncate) $string=cfStrTruncate($string,$truncate);
  1200.     return $string;
  1201. }
  1202. function cfCodePageDecode($string,$codePage){
  1203.     return @iconv($codePage,cfMGetVar('systemCodepage'),$string);
  1204.     return $string;
  1205. }
  1206.  
  1207. /**
  1208.  * @desc Protect a file name for inclusion in HTML code and return in form
  1209.  *
  1210.  * @param string $filename : system-encoded file name
  1211.  * @return string : protected filename
  1212.  */
  1213. function cfProtectFilename($filename){
  1214.     //return rawurlencode($filename);
  1215.     //$filename=str_replace('+','*weezoPlus*',$filename);
  1216.     $filename=htmlspecialchars(cfUTF8Encode($filename,false,false),ENT_QUOTES,'UTF-8');
  1217.     $filename=str_replace(' ',' ',$filename);
  1218.     return $filename;
  1219. }
  1220.  
  1221. /**
  1222.  * @desc Protect text placed into inline javascript function's args (onclick="javascript:my_fn('$s')")
  1223.  *
  1224.  * @param string $s
  1225.  * @return string
  1226.  */
  1227. function cfProtectInlineScriptTextArg($s){return addslashes(str_replace('"','"',$s));}
  1228.  
  1229. /**
  1230.  * @desc : convert back filename received through post or get (and protected with cfProtectFilename)
  1231.  *
  1232.  * @param string $filename
  1233.  * @return string : original filename
  1234.  */
  1235. function cfUnprotectFilename($filename){
  1236.     //return cfUTF8Decode(rawurldecode($filename),true,false,false);
  1237.     $filename=str_replace(chr(194).chr(160),' ',$filename);
  1238.     $filename=str_replace('*weezoAmp*','&',$filename);
  1239.     $filename=str_replace('*weezoPlus*','+',$filename);
  1240.     $filename=str_replace('\\','/',$filename);
  1241.     $filename=str_replace(''',"'",$filename);
  1242.  
  1243.     // Replace chr(160) by spaces if not part of utf8 encoding
  1244.     if(strpos($filename,chr(160))!==false){
  1245.         for($i=0;$i<strlen($filename);$i++) if($filename[$i]==chr(160) && $i>0 && ord($filename[$i-1])<128) $filename[$i]=' ';
  1246.     }
  1247.     $filename=str_replace('>','>',str_replace('<','<',str_replace(' ',' ',$filename)));
  1248. //    $filename=str_replace('&','&',$filename);
  1249.     $filename=cfUTF8Decode($filename,true,true,false);
  1250.     return $filename;
  1251. }
  1252.  
  1253. /**
  1254.  * @desc Protect a file name for inclusion in URL (to be used with ext/... .php)
  1255.  *
  1256.  * @param string $filename : system-encoded file name
  1257.  * @return string : protected filename (
  1258.  */
  1259. function cfProtectFilenameURL($filename){
  1260.     $filename=rawurlencode(cfUTF8Encode($filename,false,false));
  1261.     return $filename;
  1262. }
  1263.  
  1264. /**
  1265.  * @desc : convert back filename received through post or get (and protected with cfProtectFilename)
  1266.  *
  1267.  * @param string $filename
  1268.  * @return string : original filename
  1269.  */
  1270. function cfUnprotectFilenameURL($filename){
  1271.     return cfUTF8Decode(rawurldecode($filename),true,false,false);
  1272. }
  1273.  
  1274.  
  1275. /**
  1276.  * @desc Load language into $_ENV['weezoLng'] array
  1277.  *          If not already loaded into memory, load-it from file
  1278.  *
  1279.  * @param string $lng: language name (not used)
  1280.  */
  1281. function cfLoadLanguage($lng=false){
  1282.     // If language is already loaded into ENV array, done
  1283.     if(isset($_ENV['weezoLng'])) return;
  1284.     if(!$lng) $lng=cfGGetVar('language');
  1285.     // Load into ENV array from memory
  1286.     if(!($_ENV['weezoLng']=cfMGetVar('weezoLng'.$lng))){
  1287.         // If language not loaded into memory, load now
  1288.         if(!$lng) $lng='en';
  1289.         require_once(INCLUDE_DIR.'lng/'.$lng.'.php');
  1290.         if(isset($w_lng)){
  1291.             cfMSetVar('weezoLng'.$lng,$w_lng);
  1292.             // Then commit to ENV array
  1293.             $_ENV['weezoLng']=$w_lng;
  1294.             unset($w_lng);
  1295.         }
  1296.     }
  1297. }
  1298.  
  1299. /**
  1300.  * @return string
  1301.  * @param string $captionName
  1302.  * @param string $param1: 1st utf-8 encoded replace arg
  1303.  * @param string $param2: 2nd utf-8 encoded replace arg
  1304.  * @param string $param3: 3rd utf-8 encoded replace arg
  1305.  * @param string $forceUILanguage: true to use UI language instead of client's. Used to send alerts to UI or to log events
  1306.  * @desc return utf-8 encoded $captionName in current language (if provided replace %1 by $param1, %2 by $param2...)
  1307. */
  1308. function cfCaption($captionName,$param1=false,$param2=false,$param3=false,$forceUILanguage=false){
  1309.     if(($forceUILanguage||cfIsInApp()) && cfGGetVar('language')!=cfGGetVar('languageUI')){
  1310.         $lng=cfMGetVar('weezoLng'.cfGGetVar('languageUI'));
  1311.         $c=@$lng[$captionName];
  1312.         unset($lng);
  1313.     }
  1314.     else{
  1315.         cfLoadLanguage();
  1316.         $c=@$_ENV['weezoLng'][$captionName];
  1317.     }
  1318.  
  1319.     if(!$c) return '# '.$captionName.' #';
  1320.     $textToWrite=str_replace('&', '&',$c);
  1321.     if($param1!==false) $textToWrite=str_replace('%1',($param1),$textToWrite);
  1322.     if($param2!==false) $textToWrite=str_replace('%2',($param2),$textToWrite);
  1323.     if($param3!==false) $textToWrite=str_replace('%3',($param3),$textToWrite);
  1324.     return $textToWrite;
  1325. }
  1326.  
  1327. /**
  1328.  * @desc return true if caption is defined
  1329.  *
  1330.  * @param strin $captionName : caption
  1331.  * @return bool
  1332.  */
  1333. function cfCaptionExist($captionName){cfLoadLanguage();if(isset($_ENV['weezoLng'][$captionName])) return true; else return false;}
  1334.  
  1335. /**
  1336.  * @return string
  1337.  * @param string $captionName
  1338.  * @param string $param1 1st optional item to include in return caption (replace %1)
  1339.  * @param string $param2 2nd optional item to include in return caption (replace %2)
  1340.  * @param string $param3 3rd optional item to include in return caption (replace %3)
  1341.  * @param string $param4 4st optional item to include in return caption (replace %4)
  1342.  * @desc return $captionName in current language (if provided replace %1 by $param1, %2 by $param2...), formated for JavaScript
  1343. */
  1344. function cfCaptionJS($captionName=false,$param1=false,$param2=false){
  1345.     cfLoadLanguage();
  1346.     if(!$captionName) $textToWrite='%1';
  1347.     else{
  1348.         if(!isset($_ENV['weezoLng'][$captionName])) return '# '.$captionName.' #';
  1349.         $textToWrite=str_replace('&', '&',$_ENV['weezoLng'][$captionName]);
  1350.     }
  1351.     if($param1) $textToWrite=str_replace("%1",cfUTF8Encode($param1),$textToWrite);
  1352.     if($param2) $textToWrite=str_replace("%2",cfUTF8Encode($param2),$textToWrite);
  1353.     return addslashes($textToWrite);
  1354. }
  1355.  
  1356. /*
  1357.  ***************************************************************************************************************************
  1358.  * Async HTTPXmlRequest Functions
  1359.  ***************************************************************************************************************************
  1360.  */
  1361.  
  1362. /**
  1363.  * @desc return true if asynchronous request
  1364.  *
  1365.  */
  1366. function cfIsAsync(){return isset($_POST['asyncRequest']);}
  1367.  
  1368. /**
  1369.  * @desc echo header and xml stuff for async response
  1370.  *
  1371.  * @param string $responseNodeAttributes: attributes added to <response> node
  1372.  * @param boolean $cacheRequest: true to indicate browser to cache request
  1373.  */
  1374. function cfAsyncHeader($responseNodeAttributes='',$cacheRequest=false){
  1375.     if(isset($_ENV['cfAsyncHeader'])) return;
  1376.     $_ENV['cfAsyncHeader']=1;
  1377.     if(cfMGetVar('debugAsync') && $_SERVER['SCRIPT_NAME']!='/index.php' && $_SERVER['SCRIPT_NAME']!='/ping.php' && $_SERVER['SCRIPT_NAME']!='/pub/tools.php') {
  1378.         $_ENV['debugAsync']=microtime(true);
  1379.         ob_start();
  1380.     }
  1381.     // Classic browser async request
  1382.     if(!isset($_GET['XMLHttpScriptRequest'])){
  1383.         header('Content-Type:text/xml');
  1384.         header('P3P: policyref="/w3c/p3p.xml",CP="NON COR CURa OUR NOR NAV"');
  1385.         if($cacheRequest){
  1386.             header("Pragma:"); // Do not remove, required by IE in SSL mode
  1387.             header('Cache-Control: private');
  1388.             header('Expires: '.gmdate("D, d M Y H:i:s",time()+3600).' GMT');
  1389.         }
  1390.         else{
  1391.             header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  1392.         }
  1393.         echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<response".(($responseNodeAttributes!='')?' '.$responseNodeAttributes:'').">\n";
  1394.     }
  1395.     // Script inclusion async request
  1396.     else {
  1397.         header('P3P: policyref="/w3c/p3p.xml",CP="NON COR CURa OUR NOR NAV"');
  1398.         header('Content-Type: text/html');
  1399.         header('Expires: Mon, 26 Jul 1997 15:00:00 GMT');
  1400.         header('Cache-Control: no-cache, must-revalidate');
  1401.         header('Pragma: no-cache');
  1402.     }
  1403. }
  1404. /**
  1405.  * @desc return async response footer
  1406.  *
  1407.  * @return string
  1408.  */
  1409. function cfAsyncFooter(){
  1410.     // Debug
  1411.     if(isset($_ENV['debugAsync'])){
  1412.         // Filter
  1413.         $debug=0;
  1414.         if($daf=cfMGetVar('debugAsyncFilter')){
  1415.             if(stripos(ob_get_contents(),$daf)!==false) $debug=1;
  1416.             else foreach ($_POST as $k=>$v){
  1417.                 if(strpos($k.$v,$daf)!==false) $debug=1;
  1418.             }
  1419.         }
  1420.         // No filter
  1421.         elseif ($_SERVER['PHP_SELF']!='/ping.php' && basename($_SERVER['PHP_SELF'])!='transfers.php') $debug=1;
  1422.         if($debug){
  1423.             $resp=substr(ob_get_contents(),50);
  1424.             cfDebugSetBuffer('async',$_POST,$resp);
  1425.         }
  1426.         ob_end_flush();
  1427.     }
  1428.     if(!isset($_GET['XMLHttpScriptRequest'])) return '</response>'; else return '<script type="text/javascript">parent.mcRIP=0;</script>';
  1429. }
  1430.  
  1431. /**
  1432.  * @desc send xml data
  1433.  *
  1434.  * @param string $XMLTag : tag AND attributes : '<tag value="foo">'
  1435.  * @param string $data
  1436.  * @return xml code
  1437.  */
  1438. function cfAsyncXMLNode($XMLTag,$data){
  1439.     $blockSize=3500;
  1440.     $output='';
  1441.     if(substr($XMLTag,0,1)=='<') $XMLTag=substr($XMLTag,1);if(substr($XMLTag,-1)=='>') $XMLTag=substr($XMLTag,0,strlen($XMLTag)-1);
  1442.     if(strpos($XMLTag,' ')) $tagName=substr($XMLTag,0,strpos($XMLTag,' ')); else $tagName=$XMLTag;
  1443.     // if not gecko or output size < $blockSize
  1444.     if(strlen($data)<=$blockSize || cfGetBrowser()!='gecko') return '<'.$XMLTag.'>'.cfXMLEncode($data).'</'.$tagName.'>';
  1445.  
  1446.     // slice response in $blockSize bytes blocks
  1447.     while (strlen($data)>$blockSize) {
  1448.         $i=1; while(ord(substr($data,$blockSize-$i,1))>127) $i++; // (try to?) avoid cutting an cft8 encoded character in 2
  1449.         $output.='<addToBuffer>'.cfXMLEncode(substr($data,0,$blockSize-$i))."</addToBuffer>\n";
  1450.         $data=substr($data,$blockSize-$i);
  1451.     }
  1452.     if(strlen($data)) $output.='<addToBuffer>'.cfXMLEncode($data)."</addToBuffer>\n";
  1453.     $output.='<'.$XMLTag.' commitBuffer="true"/>';
  1454.     return $output;
  1455. }
  1456. /**
  1457.  * @desc : Return XML code that will trigger execution of a javascript function when returned to XMLHttpRequest
  1458.  *
  1459.  * @param string $script: utf-8 encoded javascript
  1460.  * @param bool $realTime: set to true to ask browser to execute commands ASAP
  1461.  * @return XML node
  1462.  */
  1463. function cfAsyncXMLJSaction($script,$realTime=false){
  1464.     if(!isset($_GET['XMLHttpScriptRequest'])) return cfAsyncXMLNode(($realTime)?'<JSRT>':'<JSAction>',$script);
  1465.     else return '<script type="text/javascript">parent.asEval(\''.addslashes($script).'\')</script>';
  1466. }
  1467. /**
  1468.  * @desc Alias for cfAsyncXMLJSaction
  1469.  *
  1470.  * @param string $script: utf-8 encoded javascript
  1471.  * @param bool $realTime: set to true to ask browser to execute commands ASAP
  1472.  * @return XML node
  1473.  */
  1474. function cfAsyncJSaction($script,$realTime=false){
  1475.     if(!isset($_GET['XMLHttpScriptRequest'])) return cfAsyncXMLNode(($realTime)?'<JSRT>':'<JSAction>',$script);
  1476.     else return '<script type="text/javascript">parent.asEval(\''.addslashes($script).'\')</script>';
  1477. }
  1478. /**
  1479.  * @desc : Return XML code that will trigger execution of a javascript alert displaying $text
  1480.  *
  1481.  * @param string $text : non-utf-8 encoded text to display
  1482.  * @return XML node
  1483.  */
  1484. function cfAsyncXMLDebug($text){return cfAsyncXMLJSaction('alert("'.addcslashes($text,'"\\').'")');}
  1485. /**
  1486.  * @desc : Return XML code that will trigger replacement of innerHTML content of HTML node with $id id attribute
  1487.  *
  1488.  * @param string $html : utf-8 innerHTML content
  1489.  * @param string $id : id of node whose innerHTML will be replaced
  1490.  * @param boolean $add : true if $html must be added to node content, false to replace
  1491.  * @return XML node
  1492.  */
  1493. function cfAsyncXMLInnerHTMLbyId($html,$id,$add=false){
  1494.     if(!isset($_GET['XMLHttpScriptRequest'])) return cfAsyncXMLNode('<innerHTML nodeId="'.$id.'"'.(($add)?' add="true"':'').'>',$html);
  1495.     else return '<script type="text/javascript">parent.dgi("'.$id.'").innerHTML'.(($add)?'+=':'=')."'".str_replace("\n",'',addcslashes($html,"'\\"))."';</script>\n";
  1496. }
  1497.  
  1498. /**
  1499.  * @desc : Return XML code that will trigger replacement of innerHTML content of HTML node(s) named $name
  1500.  *
  1501.  * @param string $html : utf-8 innerHTML content
  1502.  * @param string $name : name of node(s) whose innerHTML will be replaced
  1503.  * @param boolean $add : true if $html must be added to node content, false to replace
  1504.  * @return XML node
  1505.  */
  1506. function cfAsyncXMLInnerHTMLbyName($html,$name,$add=false){
  1507.     if(!isset($_GET['XMLHttpScriptRequest'])) return cfAsyncXMLNode('<innerHTML nodeName="'.$name.'"'.(($add)?' add="true"':'').'>',$html);
  1508.     else return 'parent.dgn("'.$name.'").innerHTML'.(($add)?'+=':'=')."'".str_replace("\n",'',addcslashes($html,"'\\"))."';\n";
  1509. }
  1510. /**
  1511.  * @desc : Return XML code that will trigger replacement of innerHTML content of HTML node(s) with $tagName tag
  1512.  *
  1513.  * @param string $html : utf-8 innerHTML content
  1514.  * @param string $tagName : tag of node(s) whose innerHTML will be replaced
  1515.  * @param boolean $add : true if $html must be added to node content, false to replace
  1516.  * @return XML node
  1517.  */
  1518. function cfAsyncXMLInnerHTMLbyTagName($html,$tagName,$add=false){
  1519.     if(!isset($_GET['XMLHttpScriptRequest'])) return cfAsyncXMLNode('<innerHTML nodeTagName="'.$tagName.'"'.(($add)?' add="true"':'').'>',$html);
  1520.     else return '<script type="text/javascript">parent.getElementsByTagName("'.$tagName.'")[0].innerHTML'.(($add)?'+=':'=')."'".str_replace("\n",'',addcslashes($html,"'\\"))."';</script>\n";
  1521. }
  1522. /**
  1523.  * @desc : Update a resource php variable value from async post
  1524.  *
  1525.  * @param string $phpVarName : name of resource var to update
  1526.  */
  1527. function cfAsyncXMLChangePhpVarValue($phpVarName,$constraints=false){
  1528.     // Change variable value
  1529.     if(isset($_POST[$phpVarName])){
  1530.         $res=cfUTF8Decode($_POST[$phpVarName]);
  1531.         if(strtolower($res)=='true') $res=true;  if(strtolower($res)=='false') $res=false;
  1532.         if(!$constraints) cfRSetVar($phpVarName,$res);
  1533.         else{
  1534.             foreach ($constraints as $v) if($res==$v) {cfRSetVar($phpVarName,$res);break;}
  1535.         }
  1536.         // Send async response
  1537.         die(cfAsyncHeader().cfAsyncFooter());
  1538.     }
  1539.     // Async controls
  1540.     elseif (isset($_POST['asUpdtName']) && $_POST['asUpdtName']==$phpVarName) {
  1541.         $_POST['asUpdtValue']=cfUTF8Decode($_POST['asUpdtValue']);
  1542.         if(!$constraints) cfRSetVar($phpVarName,$_POST['asUpdtValue']);
  1543.         else{
  1544.             foreach ($constraints as $v) if($_POST['asUpdtValue']==$v) {cfRSetVar($phpVarName,$_POST['asUpdtValue']);break;}
  1545.         }
  1546.         // Send async response
  1547.         die(cfAsyncHeader().cfAsyncFooter());
  1548.     }
  1549. }
  1550. /**
  1551.  * @desc : depending on asyncResponse, echo $output and reset, or echo $output in XML format
  1552.  *         if $asyncResponse is in $condition array (or if $condition is false), echo <$xmlTag>$output</$xmlTag>
  1553.  *        (note : XML tag may include attributes)
  1554.  *            if $exitIfXMLFlush is true, close async response and exit
  1555.  *        else just echo $output and set it to empty string.
  1556.  *
  1557.  * @param string $output
  1558.  * @param string $asyncResponse
  1559.  * @param array $condition
  1560.  * @param string $XMLTag
  1561.  * @param boolean $exitIfXMLFlush
  1562.  */
  1563. function cfAsyncOutputFlush(&$output, $asyncResponse, $condition, $XMLTag, $exitIfXMLFlush=true){
  1564.     if(!$asyncResponse) echo $output;
  1565.     elseif(!$condition || in_array($asyncResponse,$condition)){
  1566.         if(isset($_GET['XMLHttpScriptRequest'])){
  1567.             if(substr($XMLTag,0,19)=='<innerHTML nodeId="') echo cfAsyncXMLInnerHTMLbyId($output,substr($XMLTag,19,strlen($XMLTag)-21));
  1568.             if(substr($XMLTag,0,20)=='<innerHTML tagName="') echo cfAsyncXMLInnerHTMLbyId($output,substr($XMLTag,20,strlen($XMLTag)-22));
  1569.             if(substr($XMLTag,0,20)=='<innerHTML name="') echo cfAsyncXMLInnerHTMLbyId($output,substr($XMLTag,17,strlen($XMLTag)-19));
  1570.         }
  1571.         else echo cfAsyncXMLNode($XMLTag,$output);
  1572.         if($exitIfXMLFlush) die(cfAsyncFooter());
  1573.     }
  1574.     $output='';
  1575. }
  1576.  
  1577. /**
  1578.  * Real-time execute script for synchronous or asynchronous actions
  1579.  *
  1580.  * @param string $script
  1581.  */
  1582. function cfRTScript($script){
  1583.     if(cfIsMobile()) return;
  1584.     if(cfIsAsync()) echo cfAsyncXMLJSaction($script,true)."\n";
  1585.     else echo '<script type="text/javascript">'.$script.'</script>';
  1586.     flush();
  1587. }
  1588.  
  1589. /**
  1590.  ***************************************************************************************************************************
  1591.  * Drag'n drop functions
  1592.  ***************************************************************************************************************************
  1593.  */
  1594.  
  1595. /**
  1596.  * @desc set JS function called when an object is dragged onto another
  1597.  *
  1598.  * @param string $dropFunctionName : name of JS function
  1599.  * @return string HTML JS code
  1600.  */
  1601. function cfDragSetDropFunction($dropFunctionName){
  1602.     $output="<script type=\"text/javascript\">\n<!--\n";
  1603.     $output.='setDropFunction("'.$dropFunctionName."\");\n";
  1604.     return $output."\n//-->\n</script>\n";
  1605. }
  1606. /**
  1607.  * @desc add an item (image or div) to draggable items list
  1608.  *             added items list must be commited with cfDragRegisterItems (sync) or cfDragAsyncRegisterDiv (async)
  1609.  *
  1610.  * @param string $name: name (for images) or id (for div) of draggable item node
  1611.  * @param string $properties: properties of draggable item
  1612.  * @param string $initCommands: JS commands called after SET_DHTML function
  1613.  */
  1614. function cfDragAddItem($name, $properties=false, $initCommands=false){
  1615.     //if(isset($_SESSION['activeResourceId'])) cfRSetVar('dragItems',$name,$properties); else
  1616.     $_ENV['weezo']['dragItems'][$name]=$properties;
  1617.     if($initCommands){
  1618.         if(!isset($_ENV['weezo']['dragItemsInitCommands'])) $_ENV['weezo']['dragItemsInitCommands']='';
  1619.         $_ENV['weezo']['dragItemsInitCommands'].=$initCommands.";\n";
  1620.     }
  1621. }
  1622. /**
  1623.  * @desc launch JS function that creates draggable items from draggable items list
  1624.  *
  1625.  * @return string HTML JS code
  1626.  */
  1627. function cfDragRegisterItems($defaultOptions='SCROLL',$includeScriptTag=true){
  1628.     $receiverOnly='';
  1629.     if($includeScriptTag) $output="<script type=\"text/javascript\">\n"; else $output='';
  1630.     $output.="SET_DHTML(".((!$defaultOptions)?'""':$defaultOptions);
  1631.     if (isset($_ENV['weezo']['dragItems'])){
  1632.         foreach ($_ENV['weezo']['dragItems'] as $key=>$value){
  1633.             if(strpos($value,'+RECEIVER_ONLY')!==false) {
  1634.                 $receiverOnly.='drec.addElt(dgi("'.$key.'"));';
  1635.                 $value=str_replace('+RECEIVER_ONLY','',$value);
  1636.                 if(strpos($value,'+HIGHLIGHT_FUNC')!==false) $receiverOnly.='drec.setHighlightFunction(dgi("'.$key.'"),'.substr($value,15).');';
  1637.  
  1638.             }
  1639.             else $output.=",\n\"".$key.'"'.$value;
  1640.         }
  1641.     }
  1642.     $output.=");\n";
  1643.     $output.=$receiverOnly;
  1644.     if(isset($_ENV['weezo']['dragItemsInitCommands'])) $output.=$_ENV['weezo']['dragItemsInitCommands'];
  1645.     if($includeScriptTag) return $output."</script>\n"; else return $output;
  1646. }
  1647. /**
  1648.  * @desc launch JS function that creates draggable items from draggable items list (for async use, only works with div, not with img)
  1649.  *
  1650.  * @return string HTML JS code
  1651.  */
  1652. function cfDragAsyncRegisterDiv(){
  1653.     if(!isset($_ENV['weezo']['dragItems'])) return '';
  1654.     $js='';    foreach ($_ENV['weezo']['dragItems'] as $key=>$value)    $js.='ADD_DHTML("'.$key.'"'.$value.");\n";
  1655.     return cfAsyncXMLJSaction($js);
  1656. }
  1657.  
  1658.  
  1659. /*
  1660.  ***************************************************************************************************************************
  1661.  * Misc. Functions
  1662.  ***************************************************************************************************************************
  1663.  */
  1664.  
  1665. /**
  1666.  * @desc Send a ping to app if nothing has been sent for over clientPingInterval secs
  1667.  * @param mixed $step: perform test once out of $step times (to reduce execution time when called numerous times)
  1668.  *                 set to 0 not to perform test
  1669.  *                 set to 'force' to force sending, even if last ping was sent less than clientPingInterval seconds ago
  1670.  *                 set to 'backup' to ping only if last ping was send more than 3 times clientPingInterval seconds ago (from security.php)
  1671.  * @param integer $newDisconnectionInterval: if set, change app's disconnection interval
  1672.  *             (used not to disconnect while playing media on devices using "standaloneMediaPlayer")
  1673.  *
  1674.  * @return true if ping sent, false if ping not needed, null if error
  1675.  */
  1676. function cfPingUpdate($step=0, $newDisconnectionInterval=0){
  1677.     if(is_numeric($step) && $step>0){
  1678.         global $cfPingUpdate;
  1679.         if(!isset($cfPingUpdate)) $cfPingUpdate=0;
  1680.         if((++$cfPingUpdate)%$step) return false;
  1681.     }
  1682.     if(!isset($_ENV['weezoSessionId'])){
  1683.         if(wSession_id()) $_ENV['weezoSessionId']=wSession_id();
  1684.         elseif(isset($_COOKIE['WSESSID']) && $_COOKIE['WSESSID']) $_ENV['weezoSessionId']=$_COOKIE['WSESSID'];
  1685.         else return NULL;
  1686.     }
  1687.  
  1688.     // Get last ping
  1689.     if(!cfMIssetVar('weezoPings')) cfMSetVar('weezoPings',array());
  1690.     $pings=cfMGetVar('weezoPings');
  1691.     if($step==='force') $len=0;
  1692.     elseif($step==='backup') $len=cfGGetVar('clientPingInterval')*3;
  1693.     else $len=cfGGetVar('clientPingInterval');
  1694.  
  1695.     // Check if ping is needed
  1696.     if(!isset($pings[$_ENV['weezoSessionId']]) || (time()-$pings[$_ENV['weezoSessionId']]>$len)) {
  1697.         if($newDisconnectionInterval>0) $newDisconnectionInterval=max($newDisconnectionInterval,cfGGetVar('inactivityTimeBeforeDisconnect'));
  1698.  
  1699.         if(cfServerSendCommand('ping extendsTo="'.$newDisconnectionInterval.'"')){
  1700.             $pings=@cfMGetVar('weezoPings');
  1701.             $pings[$_ENV['weezoSessionId']]=time();
  1702.             cfMSetVar('weezoPings',$pings);
  1703.             return true;
  1704.         }
  1705.         return NULL;
  1706.     }
  1707.     return false;
  1708. }
  1709.  
  1710. /**
  1711.  * @return string
  1712.  * @param string $file
  1713.  * @desc return file extension
  1714. */
  1715. function cfFileExtension($file){
  1716.     if(strrpos($file,'.')===false) return '';
  1717.     return strtolower(substr($file,strrpos($file,'.')+1));
  1718. }
  1719.  
  1720. /**
  1721.  * @return string
  1722.  * @param string $file
  1723.  * @desc return file name without extension
  1724. */
  1725. function cfFileWithoutExtension($file){
  1726.     if(strrpos($file,'.')===false) return $file;
  1727.     return substr($file,0,strrpos($file,'.'));
  1728. }
  1729.  
  1730. /**
  1731.  * @desc Return file size
  1732.  *
  1733.  * @param string $completeFilename
  1734.  * @return int
  1735.  */
  1736. function cfFileSize($completeFilename){
  1737.     $size=customFileSize($completeFilename);
  1738.     if($size==8589934591) return @filesize($completeFilename); else return $size;
  1739. }
  1740.  
  1741. /**
  1742.  * @desc Read $len bytes of given file at given position: Works with files larger than 2GB
  1743.  *
  1744.  * @param string $cfn: filename
  1745.  * @param double $pos: offset from start
  1746.  * @param long $len: read length
  1747.  * @return string (or false)
  1748.  */
  1749. function cfFread($cfn,$pos,$len){
  1750.     // Below 2GB limit: use built-in functions
  1751.     if($pos<2147483648){
  1752.         if(!($fp=fopen($cfn,'rb'))) return false;
  1753.         fseek($fp,$pos);
  1754.         $data=fread($fp,$len);
  1755.         fclose($fp);
  1756.         return $data;
  1757.     }
  1758.     // Over 2GB: use custom
  1759.     $data=customFread($cfn,$pos,$len);
  1760.     customFreadFree();
  1761.     return $data;
  1762. }
  1763.  
  1764. /**
  1765.  * @return string
  1766.  * @param string $dir
  1767.  * @desc returns a clean lowercase file or path name. return false if doesn't exist
  1768. */
  1769. function cfCleanPathName($dir){
  1770.     // Shared list
  1771.     if($dir=='*resourceBasePath*') return $dir;
  1772.     elseif (substr($dir,0,19)=='*resourceBasePath*/'){
  1773.  
  1774.         $subDir=substr($dir,19);
  1775.  
  1776.         if(strpos($subDir,'/')) $dirName=substr($subDir,0,strpos($subDir,'/')); else $dirName=$subDir;
  1777.  
  1778.         // Browse shared items
  1779.         foreach (cfRGetVar('sharedItems') as $cfn=>$type) {
  1780.             // Look in subdirs
  1781.             if($type=='d' && basename($cfn)==$dirName) {
  1782.                 $dir=realpath(dirname($cfn).'/'.$subDir);
  1783.                 $dir=(strtr($dir,"\\","/"));
  1784.  
  1785.                 if(cfIsSubDir($cfn,$dir)) return $dir;
  1786.                 elseif ($dir==dirname($cfn)) return '*resourceBasePath*'; // detect *resourceBasePath*/path/..
  1787.             }
  1788.             // Look for files
  1789.             if($type=='f' && basename($cfn)==$subDir) return $cfn;
  1790.         }
  1791.         return false;
  1792.     }
  1793.     if(substr($dir,0,14)=='*resSpecific*/') return $dir; // No operation on resource specific filenames
  1794.     if($dir=='..' || $dir=='.') return false;
  1795.     if($dir=='computerRoot') return $dir;
  1796.     if(!($dir=realpath($dir))) return false;
  1797.     $dir=(strtr($dir,"\\","/"));
  1798.     if(substr($dir,-1)=='/') return substr($dir,0,strlen($dir)-1); else return $dir;
  1799. }
  1800.  
  1801. /**
  1802.  * @desc glob working with UNC
  1803.  *
  1804.  * @param string $mask : glob parameter
  1805.  * @return array
  1806.  */
  1807. function cfGlob($mask){
  1808.     if(substr($mask,-1)=='/') $mask.='*';
  1809.     $dir=str_replace('\\','/',dirname($mask)); $mask=basename($mask);
  1810.     if(!$mask || $mask=='*' || $mask=='*.*') $mask=false; else $mask='/^'.str_replace('*',".*",str_replace('?','.',str_replace('.','\\.',$mask))).'$/i';
  1811.     $res=array(); if(!$fp=@opendir($dir)) return $res;
  1812.     if(substr($dir,-1)!='/') $dir.='/';
  1813.     while (($file=readdir($fp))!==false) if($file!='.' && $file!='..') {
  1814.         if(!$mask || preg_match($mask,$file)) $res[]=$dir.$file;
  1815.     }
  1816.     closedir($fp);
  1817.     return $res;
  1818. }
  1819.  
  1820. /**
  1821.  * @desc corrects existing filename case
  1822.  *
  1823.  * @param strint $completeFilename
  1824.  * @return string
  1825.  */
  1826. function cfCorrectFilenameCase($completeFilename,$processPath=false){
  1827.     if($completeFilename=='computerRoot') return $completeFilename;
  1828.     if(strlen($completeFilename)<4) return strtoupper($completeFilename);
  1829.     $completeFilename=str_replace('\\','/',$completeFilename);
  1830.     $dir=str_replace('\\','/',dirname($completeFilename)); if(substr($dir,-1)=='/') $dir=substr($dir,0, strlen($dir)-1);
  1831.     if($processPath) $dir=cfCorrectFilenameCase($dir,true);
  1832.     $filename=strtolower(basename($completeFilename));
  1833.     foreach (cfGlob($dir.'/*') as $key=>$value) if(strtolower(basename($value))==$filename) {
  1834.         return strtoupper($value[0]).substr($value,1);
  1835.     }
  1836.     return $completeFilename;
  1837. }
  1838.  
  1839. /**
  1840.  * @return string
  1841.  * @param string $cfn
  1842.  * @desc returns the dir part of $cfn (same as PHP dirname exepted for root directories returned with a '/'
  1843. */
  1844. function cfDirName($cfn){
  1845.     if($cfn=='*resourceBasePath*') return $cfn;
  1846.     return strtr(dirname($cfn),"\\","/");
  1847. }
  1848.  
  1849. /**
  1850.  * @return string
  1851.  * @param string $path
  1852.  * @desc returns the basename part of $path (same as PHP dirname exepted for root directories returned with a '/'
  1853. */
  1854. function cfBasename($cfn){
  1855.     if($cfn=='*resourceBasePath*') return '.';
  1856.     if(substr($cfn,-1)==':'||substr($cfn,-2,1)==':') return '';
  1857.     return strtr(basename($cfn),"\\","/");
  1858. }
  1859.  
  1860. /**
  1861.  * @return string
  1862.  * @param string $path
  1863.  * @param string $file
  1864.  * @desc joins a path and a file (used to prevent '//' problems)
  1865. */
  1866. function cfJoinPathFile($path,$file){
  1867.     if(strlen($path)==0) return $file;
  1868.     if(strlen($file)==0||$file=='.') return $path;
  1869.     if($path=='computerRoot') return $file;
  1870.     if(substr($file,0,1)=='/' || substr($file,0,1)=='\\') $file=substr($file,1);
  1871.     if(substr($path,-1)=='/') return $path.$file;
  1872.     if(substr($path,-1)=='\\') return substr($path,0,strlen($path)-1).'/'.$file;
  1873.     return $path.'/'.$file;
  1874. }
  1875.  
  1876. /**
  1877.  * @return boolean
  1878.  * @param string $upperDir
  1879.  * @param string $lowerDir
  1880.  * @desc return true if $lowerDir is $upperDir or a subdirectory of $upperDir or a file included in $upperDir (or in one of it's subdirectories)
  1881. */
  1882. function cfIsSubDir($upperDir, $lowerDir){
  1883.     if($upperDir=='computerRoot') return true;
  1884.     $upperDir=strtolower($upperDir); $lowerDir=strtolower($lowerDir);
  1885.     if(substr($upperDir,-1)=='/'||substr($upperDir,-1)=='\\') $upperDir=substr($upperDir,0,strlen($upperDir)-1);
  1886.     if(cfCmpLeft($lowerDir,$upperDir)){
  1887.         if(strlen($lowerDir)==strlen($upperDir) || substr($lowerDir,strlen($upperDir),1)=='/' || substr($lowerDir,strlen($upperDir),1)=='\\') return true;
  1888.     }
  1889.     return false;
  1890. }
  1891.  
  1892. /**
  1893.  * @return result of unlink
  1894.  * @param string $dir name of dir
  1895.  * @desc unlink a non-empty dir (which possibly includes files and subdirs) : NO ACCESS RIGHTS CHECKED !!!
  1896. */
  1897. function cfUnlinkDir($dir){
  1898.     $folder=@opendir($dir);
  1899.     if(!$folder) return false;
  1900.     while (($file = @readdir($folder))!==false) {
  1901.         if ($file!='.' && $file!='..'){
  1902.             if (is_dir($dir.'/'.$file)) $result=cfUnlinkDir($dir.'/'.$file); else $result=@unlink($dir.'/'.$file);
  1903.             if(!$result) return false;
  1904.         }
  1905.     }
  1906.     @closedir($folder);
  1907.     return @rmdir($dir);
  1908. }
  1909.  
  1910. /**
  1911.  * @return string dir created or false if failed
  1912.  * @param string $dir name of dir
  1913.  * @desc create a new folder. Folder parents are created if needed : NO ACCESS RIGHTS CHECKED !!!
  1914. */
  1915. function cfMkdir($dir){
  1916.     if(!$dir || is_dir($dir)) return $dir;
  1917.     if(substr($dir,-1)=='/') $dir=substr($dir,0,strlen($dir)-1);
  1918.     $parentDir=dirname($dir);
  1919.     if(!is_dir($parentDir)){
  1920.         if(!cfMkdir($parentDir)) return false;
  1921.     }
  1922.     return @mkdir($dir);
  1923. }
  1924.  
  1925. /**
  1926.  * @desc Copy or move a dir and all its content to another location
  1927.  *
  1928.  * @param string $source : source directory
  1929.  * @param string $target : target directory
  1930.  * @param boolean $move : set to true to move instead of copy
  1931.  * @return boolean : true if all files successfully copied/moved
  1932.  */
  1933. function cfCopyDir($source, $target, $move=false){
  1934.     $err=false;
  1935.     if(is_dir($source )){
  1936.         @mkdir($target);
  1937.         $d=dir($source);
  1938.         while (($entry=$d->read())!==false){
  1939.             if ($entry == '.' || $entry == '..') continue;
  1940.             if (is_dir($Entry=$source.'/'.$entry)){
  1941.                 cfCopyDir($Entry, $target.'/'.$entry,$move);
  1942.                 continue;
  1943.             }
  1944.             if($move) {
  1945.                 $err|=@unlink($target.'/'.$entry);
  1946.                 $err|=@rename($Entry, $target.'/'.$entry);
  1947.             }
  1948.             else $err|=@copy($Entry, $target.'/'.$entry);
  1949.         }
  1950.         $d->close();
  1951.         if($move) rmdir($source);
  1952.     }
  1953.     else {
  1954.         if($move) {
  1955.             $err|=@unlink($target);
  1956.             $err|=@rename($source, $target);
  1957.         }
  1958.         else $err|=@copy($source, $target);
  1959.     }
  1960.     return $err;
  1961. }
  1962.  
  1963. /**
  1964.  * @return string name of expected response file
  1965.  * @param string $command command to send
  1966.  * @param boolean $asyncMessage: true to send message asynchronously, false to send synched, "auto" to set according to command
  1967.  * @param boolean $customSessionId: true to specify that session id has been set by application and must not be retreived from actual session
  1968.  * @desc write a command file to application for processing
  1969. */
  1970. function cfServerSendCommand($command, $asyncMessage='auto',$customSessionId=false){
  1971.  
  1972.     // If async set to auto, determine from command
  1973.     if($asyncMessage==='auto'){
  1974.         $mcmd=substr($command,0,strpos($command,' '));
  1975.         If($mcmd == "rDesk" || $mcmd == "webcam" || /*$mcmd == "refreshResource" || $mcmd == "refreshUser" ||*/ $mcmd == "deleteUser") $asyncMessage=false; else $asyncMessage=true;
  1976.     }
  1977.     // Add client IP
  1978.     if(isset($_SESSION['accountIP'])) $command .=' ip="'.$_SESSION['accountIP'].'"'; else $command .=' ip="'.$_SERVER['REMOTE_ADDR'].'"';
  1979.     // Add in-app info
  1980.     $command .=' inApp="'.((int)cfIsInApp()).'"';
  1981.  
  1982.     // Set session Id of user
  1983.     if(!$customSessionId){
  1984.         if(wSession_id()) $command .=' sessionId="'.wSession_id().'"';
  1985.         elseif (isset($_COOKIE['WSESSID'])) $command .=' sessionId="'.$_COOKIE['WSESSID'].'"';
  1986.     }
  1987.  
  1988.     // Log exchanges with app
  1989.     if(cfGGetVar('UIDebug')) cfAppendTextToFile('PHP->UI    '.(($asyncMessage)?'a':'s').'    '.$command,cfAppDataRootDir().'/exchanges.txt',false);
  1990.  
  1991.     // Send command to applicationz
  1992.     $try=-1; while(!customSendCommand($command, (int)$asyncMessage, (string)cfMGetVar('mailslotIndex')) && ++$try<3) sleep(1);;
  1993.     if(cfGGetVar('UIDebug')) cfAppendTextToFile('PHP->UI    ok',cfAppDataRootDir().'/exchanges.txt',false);
  1994.  
  1995.     if($try==3 && cfGGetVar('weezoCrashMonitor')){
  1996.         $wok=null;
  1997.         $procs=false;$procs=@win32_ps_list_procs();
  1998.         if($procs) foreach ($procs as $proc) {
  1999.             $wok=false;
  2000.             if(strtolower(basename($proc['exe']))=='weezo.exe') {$wok=true;break;}
  2001.         }
  2002.         if($wok===false) customExecFork(cfAppBinDir().'/weezoReboot.exe','SW_HIDE','restart');
  2003.         return false;
  2004.     }
  2005.     return true;
  2006. }
  2007. function cfServerSendCmd($command, $args=false, $asyncMessage='auto',$customSessionId=false){
  2008.     if($args) {foreach ($args as $k=>$v) $command.=' '.$k.'="'.addslashes($v).'"';}
  2009.     cfServerSendCommand($command,$asyncMessage,$customSessionId);
  2010. }
  2011.  
  2012.  
  2013. /**
  2014.  * @return void
  2015.  * @param bool $closeHEAD inserts </HEAD> tag only if closeHEAD==true (generaly used to add js code)
  2016.  * @param array $options: 'noCommon.js': do not include common.js script
  2017.  * @desc Inserts complete HTML stuff and HEAD of page : doctype, html, head, title, charset, CSS
  2018.  *       CSS file name is obtained from user configuration
  2019. */
  2020. function cfInsertHEAD($closeHEAD=true,$options=array()){
  2021.     @header('P3P: policyref="/w3c/p3p.xml",CP="NON COR CURa OUR NOR NAV"');
  2022.     @header('Keep-Alive: timeout=15, max=2000');
  2023.     @header('Proxy-Connection: Keep-Alive');
  2024.     @header('Cache-Control: no-cache');
  2025.  
  2026.     /**
  2027.      * HTML Output
  2028.      */
  2029.     if(cfBGetVar('output')=='html' || !cfBGetVar('output')){
  2030.         echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">'."\n";
  2031.         echo '<html><head>'."\n";
  2032.         if(isset($_SERVER['HTTPS'])) echo '<link rel="shortcut icon" href="gfx/lock.ico">';// else echo '<link rel="shortcut icon" href="/favicon.ico">';
  2033.  
  2034.         // Charset
  2035.         echo '<meta http-equiv="content-type" content="text/html; charset=utf-8">'."\n";
  2036.  
  2037.         // Windows skin
  2038.         if(cfIsInApp()) echo '<meta http-equiv="MSThemeCompatible" CONTENT="Yes">'."\n";
  2039.  
  2040.         // IE8 compatibility
  2041.         //if(cfGetBrowser()=='ie') echo '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />'."\n";
  2042.  
  2043.         // Insert extra meta tags
  2044.         echo cfRGetVar('meta');
  2045.         if(isset($_ENV['meta'])) echo $_ENV['meta'];
  2046.  
  2047.         // Title
  2048.         if(cfIsResource()) echo '<title>'.cfUTF8Encode(cfRGetVar('name')).'</title>'."\n";
  2049.         else echo '<title>'.cfUTF8Encode(cfGGetVar('pageTitle')).'</title>'."\n";
  2050.  
  2051.         // Theme
  2052.  
  2053.         // Use Content Delivery Network
  2054.         if(cfCDNPrefix())
  2055.             echo '<link rel="stylesheet" type="text/css" href="'.cfCDNPrefix().'/themes/'.basename(cfAppThemeDir(true))."-theme.css\">\n";
  2056.         // Direct files access
  2057.         else
  2058.             echo '<link rel="stylesheet" type="text/css" href="/themes/common.css?v='.cfGGetVar('appVersion').'&theme='.str_replace('/','%2F',cfAppThemeDir(true))."\">\n";
  2059.  
  2060.         // Javascript
  2061.         echo "<script type=\"text/javascript\" language=\"javascript\">\n";
  2062.         echo 'var phpBrowser="'.cfGetBrowser().'"';
  2063.         echo ',bBrowser="'.cfBGetVar('name').'"';
  2064.         echo ',winFrames='.((cfTGetVar('frames'))?'1':'0');
  2065.         echo ',pingInterval='.(max(cfGGetVar('clientPingInterval'),cfBGetVar('clientPingInterval'),1)*1000);
  2066.         echo ',scriptMimeType="'.((cfBGetVar('output')=='xhtml-mp')?'application/ecmascript':'text/javascript').'"';
  2067.         echo ',PHP_SELF="'.$_SERVER['PHP_SELF'].'"';
  2068.         echo ',rID="'.cfRGetVar('id').'"';
  2069.         echo ',isApp='.((cfIsInApp())?'1':'0');
  2070.         echo ',noPopup='.((cfHGetVar('noPopup'))?'1':'0');
  2071.         echo ',imgFadeSteps='.(int)(cfBGetVar('imgFadeSteps'));
  2072.         echo ',dragNLaunchThreshold='.((cfGGetVar('dragNLaunchThreshold')!==false)?cfGGetVar('dragNLaunchThreshold'):'100');
  2073.         echo ',dragNLaunchFriction='.((cfGGetVar('dragNLaunchFriction')!==false)?cfGGetVar('dragNLaunchFriction'):'0.005');
  2074.         echo ',loadingIconURL="/gfx/loading.gif";';
  2075.         if(cfGGetVar('PHPDebug')) echo "var PHPDebug=1;\n";
  2076.  
  2077.         // insert javascript resource id (used by async requests)
  2078.         if(substr($_SERVER['PHP_SELF'],0,5)=='/res/' && isset($_SESSION['activeResourceId'])) echo 'var resId="'.$_SESSION['activeResourceId']."\";\n";
  2079.         //if(!cfGGetVar('PHPDebug')) echo 'noAsyncJSError=true;'; else  echo 'noAsyncJSError=false;';
  2080.         echo "noAsyncJSError=0;\n";
  2081.         // Post data used for window reload
  2082.         if(count($_POST)) {
  2083.             echo 'var reloadPostData="';
  2084.             $i=0;foreach ($_POST as $k=>$v) echo (($i++)?'&':'').$k.'='.base64_encode($v);
  2085.             echo "\";\n";
  2086.         }
  2087.  
  2088.         if(cfIsInApp()){
  2089.             echo 'document.onmousemove=function(event){return (W.event && W.event.srcElement && (W.event.srcElement.tagName=="INPUT"||W.event.srcElement.tagName=="TEXTAREA"));}'."\n";
  2090.             if(!cfGGetVar('UIDebug')) echo 'function onrightclick(e){return (W.event && W.event.srcElement && (W.event.srcElement.tagName=="INPUT"||W.event.srcElement.tagName=="TEXTAREA"));}'."\n";
  2091.         }
  2092.         echo "</script>\n";
  2093.  
  2094.         // Common js functions
  2095.         if(!isset($options['noCommon.js'])) echo cfScriptLink('common.js');
  2096.  
  2097.         // Insert theme specific stuff
  2098.         if(cfTGetVar('extraHeader') && !isset($options['noExtraHeader'])) echo cfTGetVar('extraHeader');
  2099.  
  2100.         // Insert window client scripts
  2101.         if(substr($_SERVER['PHP_SELF'],0,5)=='/res/') {
  2102.             echo cfScriptLink('winClient.js');
  2103.             // Set resource to ping server if frameless theme or published resource
  2104.             if((!cfTGetVar('frames') && !isset($_ENV['winNoBar']) && !cfIsInApp()) || cfUGetVar('id')=='standalone') {
  2105.                 echo '<script type="text/javascript">if(winMe&&winMe.setBar) winMe.setBar("'.addcslashes(cfUTF8Encode(cfRGetVar('name')),'"\\').'","'.cfUTF8Encode(cfRGetVar('resourceIcon')).'","'.((isset($_ENV['winCloseURL']))?$_ENV['winCloseURL']:'/index.php').'");';
  2106.                 echo 'var pingInt = setInterval("ping()",pingInterval);';
  2107.                 echo "</script>\n";
  2108.             }
  2109.         }
  2110.     }
  2111.  
  2112.     // Close head
  2113.     if ($closeHEAD) echo "</head>\n";
  2114.  
  2115.     // Send to browser
  2116.     flush();
  2117. }
  2118.  
  2119. /**
  2120.  * @return void
  2121.  * @param bool $closeHEAD inserts </HEAD> tag only if closeHEAD==true (generaly used to add js code)
  2122.  * @desc Inserts Minimal HTML stuff and HEAD of page : doctype, html, head, title, charset
  2123. */
  2124. function cfInsertBasicHEAD($closeHEAD=true, $isFrameset=false){
  2125.     @header('P3P: policyref="/w3c/p3p.xml",CP="NON COR CURa OUR NOR NAV"');
  2126.     @header('Connection: Keep-Alive');
  2127.     @header('Keep-Alive: timeout=15, max=2000');
  2128.     @header('Proxy-Connection: Keep-Alive');
  2129.  
  2130.     echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 '.(($isFrameset)?'Frameset':'Transitional').'//EN">'."\n";
  2131.     echo '<HTML><HEAD>'."\n";
  2132.     echo '<meta http-equiv="content-type" content="text/html; charset=utf-8">'."\n";
  2133.     echo '<TITLE>'.cfGGetVar('pageTitle').'</TITLE>'."\n";
  2134.     // Scripts
  2135.     echo "<script type=\"text/javascript\" language=\"javascript\">\n";
  2136.     echo "function dgi(oid){return document.getElementById(oid);}\n";
  2137.     // Insert javascript resource id (used by async requests)
  2138.     if(substr($_SERVER['PHP_SELF'],0,5)=='/res/') if(isset($_SESSION['activeResourceId'])) echo 'var resId="'.$_SESSION['activeResourceId']."\";";
  2139.     echo "</script>\n";
  2140.  
  2141.     if ($closeHEAD) echo "</HEAD>\n";
  2142. }
  2143.  
  2144. /**
  2145.  * @desc swap values of paramters
  2146.  *
  2147.  * @param mixed $a
  2148.  * @param mixed $b
  2149.  */
  2150. function cfSwap(&$a,&$b){$c=$a;$a=$b;$b=$c;unset($c);}
  2151.  
  2152. /**
  2153.  * @desc Check if $a & $b are set, and if $a=$b. Must be used with @
  2154.  *
  2155.  * @param mixed $a
  2156.  * @param mixed $b
  2157.  * @return boolean
  2158.  */
  2159. function cfIsEq($a,$b){
  2160.     if(!isset($a)||!isset($b)) return false;
  2161.     return $a===$b;
  2162. }
  2163.  
  2164. /**
  2165.  * @desc Return item of an array. used to retreive unique item of a function returning an array, without setting temporary var
  2166.  *
  2167.  * @param array $f
  2168.  * @param string $key
  2169.  * @param string $key2
  2170.  * @return mixed
  2171.  */
  2172. function cfArrayItem($f,$key,$key2=null){
  2173.     if($key2) return @$f[$key][$key2];
  2174.     return @$f[$key];
  2175. }
  2176.  
  2177. /**
  2178.  * @desc Explodes a 2 level string into a 2 dimensional array
  2179.  *         Ex: "a=b,c=d" returns array('a'=>'b','c'=>'d');
  2180.  *
  2181.  * @param string $sepMain: 1st separator (, in sample)
  2182.  * @param string $sep: 2nd separator (= in sample)
  2183.  * @param string $str: string to explode
  2184.  * @param bool $trim: true to trim items
  2185.  * @return array
  2186.  */
  2187. function cfExplode2Levels($sepMain,$sep,$str,$trim=1){
  2188.     $r=array();
  2189.     foreach (@explode($sepMain,$str) as $v){
  2190.         if($trim) $v=trim($v);
  2191.         if($pos=@strpos($v,$sep)){
  2192.             $k=substr($v,0,$pos); if($trim) $k=trim($k);
  2193.             $v=substr($v,$pos+1); if($trim) $v=trim($v);
  2194.             $r[$k]=$v;
  2195.         }
  2196.         else $r[$v]=false;
  2197.     }
  2198.     return $r;
  2199. }
  2200.  
  2201. /**
  2202.  * @desc Compare left-side of strings
  2203.  *
  2204.  * @param string $str
  2205.  * @param string $needle
  2206.  * @return boolean
  2207.  */
  2208. function cfCmpLeft($str, $needle){return substr($str,0,strlen($needle))===$needle;}
  2209.  
  2210. /**
  2211.  * @desc Compare right-side of strings
  2212.  *
  2213.  * @param string $str
  2214.  * @param string $needle
  2215.  * @return boolean
  2216.  */
  2217. function cfCmpRight($str, $needle){return substr($str,-strlen($needle))===$needle;}
  2218.  
  2219. /**
  2220.  * @desc Shorten string
  2221.  *
  2222.  * @param string $str
  2223.  * @param int $len: nb chars
  2224.  */
  2225. function cfStrShorten($str, $len){return substr($str,0,strlen($str)-$len);}
  2226.  
  2227. /**
  2228.  * @Analyze txt and return line break/carriage return patern
  2229.  *
  2230.  * @param string $txt
  2231.  * @return string "\n", "\r", "\n\r", "\r\n"
  2232.  */
  2233. function cfStrLBPattern(&$txt){
  2234.     if(($r=strpos($txt,"\r"))===false) return "\n";
  2235.     if(($n=strpos($txt,"\n"))===false) return "\r";
  2236.     return ($r<$n)?"\r\n":"\n\r";
  2237. }
  2238.  
  2239. /**
  2240.  * @desc unpack replacement for single response
  2241.  *
  2242.  * @param char $a
  2243.  * @param mixed $b
  2244.  * @return mixed
  2245.  */
  2246. function cfUnpack($a,$b){$u=unpack($a,$b);return $u[1];}
  2247.  
  2248. /**
  2249.  * @desc Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled
  2250.  *
  2251.  * @author: Tim Eckel - Date: 12/17/04 - Project: FreeRingers.net - Freely distributable.
  2252.  */
  2253. function fastimagecopyresampled(&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 3) {
  2254.   //
  2255.   // Optional "quality" parameter (defaults is 3).  Fractional values are allowed, for example 1.5.
  2256.   // 1 = Up to 600 times faster.  Poor results, just uses imagecopyresized but removes black edges.
  2257.   // 2 = Up to 95 times faster.  Images may appear too sharp, some people may prefer it.
  2258.   // 3 = Up to 60 times faster.  Will give high quality smooth results very close to imagecopyresampled.
  2259.   // 4 = Up to 25 times faster.  Almost identical to imagecopyresampled for most images.
  2260.   // 5 = No speedup.  Just uses imagecopyresampled, highest quality but no advantage over imagecopyresampled.
  2261.  
  2262.   if (empty($src_image) || empty($dst_image)) { return false; }
  2263.   if ($quality <= 1) {
  2264.     $temp = imagecreatetruecolor ($dst_w + 1, $dst_h + 1);
  2265.     imagecopyresized ($temp, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w + 1, $dst_h + 1, $src_w, $src_h);
  2266.     imagecopyresized ($dst_image, $temp, 0, 0, 0, 0, $dst_w, $dst_h, $dst_w, $dst_h);
  2267.     imagedestroy ($temp);
  2268.   } elseif ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) {
  2269.     $tmp_w = $dst_w * $quality;
  2270.     $tmp_h = $dst_h * $quality;
  2271.     $temp = imagecreatetruecolor ($tmp_w + 1, $tmp_h + 1);
  2272.     imagecopyresized ($temp, $src_image, $dst_x * $quality, $dst_y * $quality, $src_x, $src_y, $tmp_w + 1, $tmp_h + 1, $src_w, $src_h);
  2273.     imagecopyresampled ($dst_image, $temp, 0, 0, 0, 0, $dst_w, $dst_h, $tmp_w, $tmp_h);
  2274.     imagedestroy ($temp);
  2275.   } else {
  2276.     imagecopyresampled ($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
  2277.   }
  2278.   return true;
  2279. }
  2280.  
  2281. /**
  2282.  * @desc Wrapper for createJPG exe
  2283.  *
  2284.  * @param string $sourceFile: source image
  2285.  * @param string $destFile: destination file
  2286.  * @param integer $destMaxWidth
  2287.  * @param integer $destMaxHeight
  2288.  * @param integer$jpgQuality: 0 for default value
  2289.  */
  2290. function cfCreateJPG($sourceFile,$destFile,$destMaxWidth, $destMaxHeight,$jpgQuality=false,$resampleQuality=false,$square=false){
  2291.     // Round width & height values as createJPG fails on non-integers
  2292.     $destMaxWidth=round($destMaxWidth); $destMaxHeight=round($destMaxHeight);
  2293.  
  2294.     // Resize image using GDI, and if GDI method fails, use createJPG
  2295.     if(!customResizeJPG($sourceFile,$destFile,$destMaxWidth,$destMaxHeight,$jpgQuality,$resampleQuality,(int)$square)){
  2296.  
  2297.     /*
  2298.     'CreateJPG Command line arguments :
  2299.     '1: images path (if .jpg, process single image)
  2300.     '2: thumbnail(s) path (if source is .jpg, filename of output) or "check" to see if a thumbnail can be generated
  2301.     '3: max width
  2302.     '4: max height
  2303.     '5: filter ("images" for imgas only or "all" to try to generate thumbnails from all files or "check" to see if a thumbnail can be generated) (default: images)
  2304.     '6: extra processing : "crop" (for crop with external zoom factor), "square" (for 1/1 crop) or "no" to preserve input ratio
  2305.     '7: enlarge ratio for cropped thumbnails
  2306.     '8: jpg quality (0-100)
  2307.      *
  2308.      *
  2309.     */
  2310.         cfExecNoFork(cfAppBinDir().'\createJPG.exe','SW_HIDE','"'.$sourceFile.'" "'.$destFile.'" '.$destMaxWidth.' '.$destMaxHeight.' images '.(($square)?'crop':'no').' 1'.(($jpgQuality)?$jpgQuality:cfHGetVar('thumbnailJPGQuality',DEFAULT_JPG_QUALITY)));
  2311.     }
  2312. }
  2313.  
  2314. /**
  2315.  * @return boolean : result of operation, or jpg file if $destFile=='return'
  2316.  * @param string $sourceFile : source filename
  2317.  * @param int $sourceWidth (optional) : width of source image (if not present, this value is obtained from source file), in px
  2318.  * @param int $sourceHeight (optional) : height of source image (if not present, this value is obtained from source file), in px
  2319.  * @param string $destFile (optional) : created image filename.
  2320.  *                 If not given send image to Apache output. If given and extension!=".jpg" && !=".jpeg", add ".jpg"
  2321.  *                 if "return", return as function result
  2322.  * @param int $destMaxWidth (optional) : max width of created image in px. If not given, don't resize the image
  2323.  * @param int $destMaxHeight (optional) : max height of created image in px. If not given, don't resize the image
  2324.  * @param int $resampleQuality (optional) : 1 (fast, bad quality) to 5 (slow, good quality)
  2325.  * @param int $JPGQuality (optional) : jpg quality (1-100)
  2326.  * @param int $angle (optional) : image rotation angle
  2327.  * @param bool $square (optional) : create a square image by croping source
  2328.  * @param int $stretchSmallImages (optional) : stretch images if smaller than $destMaxWidth && $destMaxHeight
  2329.  * @desc creates a jpg resized (or not) image, send it to file or to browser output
  2330. */
  2331. function cfCreateResizedJPG($sourceFile, $sourceWidth=0, $sourceHeight=0, $destFile='', $destMaxWidth=0, $destMaxHeight=0, $resampleQuality=false, $JPGQuality=false, $angle=0, $square=false, $stretchSmallImages=true){
  2332.     if(!file_exists($sourceFile)) return false;
  2333.  
  2334.     $result=true;
  2335.     $ext=cfFileExtension($sourceFile);
  2336.  
  2337.     // default resize method: 1 (worst,fastest) - 5 (better, slowest)
  2338.     if($resampleQuality===false || !is_numeric($resampleQuality)) {
  2339.         $resampleQuality=cfHGetVar('imageResampleQuality',DEFAULT_RESIZE_METHOD);
  2340.         $resampleQuality=((cfRGetVar('imageResampleQuality'))?cfRGetVar('imageResampleQuality'):((cfGGetVar('imageResampleQuality'))?cfGGetVar('imageResampleQuality'):DEFAULT_RESIZE_METHOD));
  2341.     }
  2342.  
  2343.     // Default output jpg quality (0-100)
  2344.     if($JPGQuality===false || !is_numeric($JPGQuality)){
  2345.         $JPGQuality=cfHGetVar('thumbnailJPGQuality',DEFAULT_JPG_QUALITY);
  2346.     }
  2347.     if($destFile!='' && $destFile!='return'){
  2348.         if (strtolower(substr(strrchr($destFile,"."),1))!="jpg" && strtolower(substr(strrchr($destFile,"."),1))!="jpeg") $destFile=$destFile.".jpg";
  2349.         if (!is_dir(dirname($destFile))) return false;
  2350.     }
  2351.  
  2352.     // Get source width & height
  2353.     if($sourceWidth==0 || $sourceHeight==0) {
  2354.         if($ext=='itc'){
  2355.             if(!($sourceImage=imagecreatefromstring(substr(file_get_contents($sourceFile),500)))) return false;
  2356.             $sourceWidth=imagesx($sourceImage); $sourceHeight=imagesy($sourceImage);
  2357.         }
  2358.         elseif($ext=='itc2'){
  2359.             if(!($sourceImage=imagecreatefromstring(substr(file_get_contents($sourceFile),492)))) return false;
  2360.             $sourceWidth=imagesx($sourceImage); $sourceHeight=imagesy($sourceImage);
  2361.         }
  2362.         else list($sourceWidth, $sourceHeight, $type, $attr) = @getimagesize($sourceFile);
  2363.     }
  2364.     if($angle!=0 && $angle!=180) cfSwap($sourceWidth,$sourceHeight);
  2365.  
  2366.     if($destMaxWidth && !$destMaxHeight) $destMaxHeight=3*$destMaxWidth/4;
  2367.     if(!$destMaxWidth && $destMaxHeight) $destMaxWidth=4*$destMaxHeight/2;
  2368.  
  2369.     // If no resize or processing needed, directly send to output / return
  2370.     if(((!$destFile||$destFile=='return') && !$angle) && (!$destMaxHeight || !$destMaxWidth || ($destMaxWidth==$sourceWidth && $destMaxHeight==$sourceHeight) || ($sourceWidth < $destMaxWidth && $sourceHeight < $destMaxHeight && !$stretchSmallImages))){
  2371.         cfLog('send unresized image to output '.$sourceFile, LOG_DBG);
  2372.         if($ext=='itc'){
  2373.             if($destFile=='return') return substr(file_get_contents($sourceFile),500);
  2374.             header("Content-type: image/png");
  2375.             echo substr(file_get_contents($sourceFile),500);
  2376.         }
  2377.         elseif($ext=='itc2'){
  2378.             if($destFile=='return') return substr(file_get_contents($sourceFile),492);
  2379.             header("Content-type: image/png");
  2380.             echo substr(file_get_contents($sourceFile),492);
  2381.         }
  2382.         else{
  2383.             if($destFile=='return') return @readfile($sourceFile);
  2384.             header("Content-type: ".mime_content_type($sourceFile)); //XXXX
  2385.             @readfile($sourceFile);
  2386.         }
  2387.         if(isset($sourceImage)) imagedestroy($sourceImage);
  2388.         return true;
  2389.     }
  2390.  
  2391.     // Alternate method: use createJPG to resize images
  2392.     if(!cfGGetVar('disableCreateJPG') && ($ext=='jpg'||$ext=='bmp'||$ext=='gif'||$ext=='png') && $angle==0 && $destMaxWidth>0 && $destMaxHeight>0){
  2393.         if(!$destFile || $destFile=='return'){
  2394.             $tmpFile=cfAppTempDir().'/tmp_'.rand().'.jpg';
  2395.             cfCreateJPG($sourceFile,$tmpFile,$destMaxWidth,$destMaxHeight,$JPGQuality,$resampleQuality,$square);
  2396.             if(!$destFile) {echo file_get_contents($tmpFile); $result=true;}
  2397.             else $result=file_get_contents($tmpFile);
  2398.             @unlink($tmpFile);
  2399.             return $result;
  2400.         }
  2401.         else{
  2402.             cfCreateJPG($sourceFile,$destFile,$destMaxWidth,$destMaxHeight,$JPGQuality,$resampleQuality,$square);
  2403.             return true;
  2404.         }
  2405.     }
  2406.  
  2407.     // if destMaxWidth && destMaxHeight are provided or if rotation or if write to file, process image
  2408.     switch($ext) {
  2409.         case 'jpg':
  2410.         case 'jpeg':
  2411.             if(!($sourceImage=@imagecreatefromjpeg($sourceFile))) return false;
  2412.         break;
  2413.         case 'gif':
  2414.             if(!($sourceImage=@imagecreatefromgif($sourceFile))) return false;
  2415.         break;
  2416.         case 'wbmp':
  2417.             if(!($sourceImage=@imagecreatefromwbmp($sourceFile)) || !(imagetypes() & IMG_WBMP)) return false;
  2418.         break;
  2419.         case 'bmp':
  2420.         require_once(INCLUDE_DIR.'bmp.php');
  2421.             if(!($sourceImage=@imagecreatefrombmp($sourceFile))) return false;
  2422.         break;
  2423.         case 'png':
  2424.             if(!($sourceImage=@imagecreatefrompng($sourceFile)) || !(imagetypes() & IMG_PNG)) return false;
  2425.         case 'itc':
  2426.         case 'itc2':
  2427.         break;
  2428.         default:
  2429.         return false; // unsupported image format
  2430.     }
  2431.  
  2432.     // rotate source image if needed
  2433.     if($angle) $sourceImage=imagerotate($sourceImage,-$angle,0);
  2434.  
  2435.     // if destMaxWidth && destMaxHeight are provided, resize
  2436.     if($destMaxWidth>0 && $destMaxHeight>0){
  2437.         if(false && $destMaxWidth>=$sourceWidth && $destMaxHeight>=$sourceHeight) // Don't resize small images
  2438.             {$width=$sourceWidth; $height=$sourceHeight;}
  2439.         else{
  2440.             if($square) {$height=$width=$destMaxWidth;}
  2441.             elseif(($destMaxWidth/$destMaxHeight)>($sourceWidth/$sourceHeight)) {$width=$sourceWidth*$destMaxHeight/$sourceHeight; $height=$destMaxHeight;}
  2442.             else {$width=$destMaxWidth; $height=$sourceHeight*$destMaxWidth/$sourceWidth;}
  2443.         }
  2444.  
  2445.         // Create destination image
  2446.         $destImage = imagecreatetruecolor($width,$height);
  2447.  
  2448.         // If image must be squared
  2449.         $srcX=$srcY=0;
  2450.         if($square){
  2451.             if($sourceWidth>$sourceHeight) $srcX=($sourceWidth-$sourceHeight)/2; else $srcY=($sourceHeight-$sourceWidth)/2;
  2452.         }
  2453.  
  2454.         // Resize / resample
  2455.         if($resampleQuality>1) fastimagecopyresampled($destImage, $sourceImage, 0, 0, $srcX, $srcY, $width, $height, $sourceWidth-2*$srcX, $sourceHeight-2*$srcY,$resampleQuality);
  2456.         else imagecopyresized($destImage, $sourceImage, 0, 0, $srcX, $srcY, $width, $height, $sourceWidth-2*$srcX, $sourceHeight-2*$srcY);
  2457.         imagedestroy($sourceImage);
  2458.  
  2459.         // directly send to output
  2460.         if($destFile=='') {
  2461.             cfLog('send resized image to output '.$sourceFile, LOG_DBG);
  2462.             header("Content-type: image/jpeg");
  2463.             imagejpeg($destImage,null,$JPGQuality);
  2464.         }
  2465.         // Return image as function return
  2466.         elseif ($destFile=='return'){
  2467.             // Activate outupt buffering
  2468.             ob_start(); if(ob_get_length())    $tmp=ob_get_clean(); else $tmp=false;
  2469.             // Output image
  2470.             imagejpeg($destImage,null,$JPGQuality);
  2471.             // Get image from buffer
  2472.             $result=@ob_get_clean(); if($tmp) echo $tmp;
  2473.         }
  2474.         // send to file
  2475.         else imagejpeg($destImage,$destFile,$JPGQuality);
  2476.  
  2477.         imagedestroy($destImage);
  2478.     }
  2479.     //no resize
  2480.     else {
  2481.         cfLog('write unresized image to file '.$destFile, LOG_DBG);
  2482.  
  2483.         // Send image to string (for download speed limitation)
  2484.         if($destFile=='return')
  2485.             // Activate outupt buffering
  2486.             ob_start(); if(ob_get_length())    $tmp=ob_get_clean(); else $tmp=false;
  2487.             // Output image
  2488.             imagejpeg($sourceImage,null,$JPGQuality);
  2489.             // Get image from buffer
  2490.             $result=@ob_get_clean(); if($tmp) echo $tmp;
  2491.         // directly send to output
  2492.         elseif($destFile=='') {
  2493.             cfLog('send resized image to output '.$sourceFile, LOG_DBG);
  2494.             header("Content-type: image/jpeg");
  2495.             imagejpeg($sourceImage,null,$JPGQuality);
  2496.             }
  2497.         // send to file
  2498.         else
  2499.             imagejpeg($sourceImage,$destFile,$JPGQuality);
  2500.  
  2501.         imagedestroy($sourceImage);
  2502.     }
  2503.  
  2504.     return $result;
  2505. }
  2506.  
  2507.  
  2508. /**
  2509.  * @desc Return dimensions of size constrained thumbnail
  2510.  *
  2511.  * @param int $sourceWidth
  2512.  * @param int $sourceHeight
  2513.  * @param int $destMaxWidth
  2514.  * @param int $destMaxHeight
  2515.  * @return array(width, height)
  2516.  */
  2517. function cfThumbnailDimensions($sourceWidth,$sourceHeight,$destMaxWidth,$destMaxHeight,$stretch=false){
  2518.     if($sourceHeight*$sourceWidth==0) return array(0,0);
  2519.     if(($destMaxWidth/$destMaxHeight)>($sourceWidth/$sourceHeight)) {$width=$sourceWidth*$destMaxHeight/$sourceHeight; $height=$destMaxHeight;}
  2520.     else {$width=$destMaxWidth; $height=$sourceHeight*$destMaxWidth/$sourceWidth;}
  2521.     if((!$stretch)&&$width>$sourceWidth) return array($sourceWidth,$sourceHeight);
  2522.     return array(floor($width),floor($height));
  2523. }
  2524.  
  2525. /**
  2526.  * @desc return protocol://host:port of server
  2527.  *
  2528.  * @return string
  2529.  */
  2530. function cfHostName(){
  2531.     if(cfGGetVar('hostName')) return cfGGetVar('hostName');
  2532.     $host=(isset($_SERVER['HTTP_HOST']) && !cfIsOnLAN($_SERVER['HTTP_HOST']))?$_SERVER['HTTP_HOST']:$host=$_SERVER['SERVER_NAME'];
  2533.     return ((isset($_SERVER['HTTPS']))?'https':'http').'://'.$host.':'.$_SERVER['SERVER_PORT'];
  2534. }
  2535.  
  2536. /**
  2537.  * @desc return protocol://host:port of localhost, false if called from CLI
  2538.  *
  2539.  * @return string
  2540.  */
  2541. function cfLocalhostName(){
  2542.     if(!isset($_SERVER['SERVER_PORT'])) return false;
  2543.     return ((isset($_SERVER['HTTPS']))?'https':'http').'://127.0.0.1:'.$_SERVER['SERVER_PORT'];
  2544. }
  2545.  
  2546. /**
  2547.  * @desc return protocol://IP:port of server, where IP is external IP (initialized by setExternalIP in serverManagement.php, by UI
  2548.  *
  2549.  * @return string
  2550.  */
  2551. function cfExternalHostName(){
  2552.     return cfGGetVar('protocol').'://'.cfGGetVar('externalIP').((cfGGetVar('serverPort')==80||cfGGetVar('serverPort')==443)?'':':'.cfGGetVar('serverPort')).'/';
  2553. }
  2554.  
  2555. /**
  2556.  * @desc reture true if given IP matches with LAN mask (also works for 'localhost')
  2557.  *
  2558.  * @param string $ip
  2559.  * @return bool
  2560.  */
  2561. function cfIsOnLAN($ip=0){
  2562.     if(!$ip) $ip=$_SERVER['REMOTE_ADDR'];
  2563.     if($ip=='localhost') return true; // prod
  2564.     $ip_long=ip2long($ip);
  2565.     foreach (cfExplode2Levels(' ','/',cfGGetVar('httpdLANFilter')) as $net=>$mask){
  2566.         $net=ip2long($net);
  2567.         $mask=ip2long($mask);
  2568.         if (($ip_long & $mask) == $net) return true;
  2569.     }
  2570.     return $ip==='127.0.0.1';
  2571. }
  2572.  
  2573. /**
  2574.  * @desc : check if is IP adress
  2575.  *
  2576.  * @param string $address : adress to check
  2577.  * @return boolean : result
  2578.  */
  2579. function cfIsIP($address){
  2580.     return (ereg('^((([*]|25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]{1}[0-9]|[1-9]).){1}(([*]|25[0-5]|2[0-4][0-9]|[1]{1}[0-9]{2}|[1-9]{1}[0-9]|[0-9]).){2}(([*]|25[0-5]|2[0-4][0-9]|[1]{1}[0-9]{2}|[1-9]{1}[0-9]|[0-9]){1}))$',$address));
  2581. }
  2582.  
  2583. /**
  2584.  * @desc generate "encoded" URL to a file out of document root, using /ext/download.php
  2585.  * @return void
  2586.  * @param string $urlEncodedfileName
  2587.  * @param array $complement : extra information included in URL, to be used by ext/download.php:
  2588.  *             key values: q
  2589.  *             reencoded bitrate: q[quality]size[width]x[height]offset[offset]source
  2590.  *             still image (screenshot): image/w[width]/x[height]/
  2591.  * @param string $addressMode : $addressMode == "relative" : generate adress without host name,
  2592.                      $addressMode == "absolute" : generate adress with host name (used for files accessed by external programs (winamp, media player...))
  2593.  * @param string $preUTF8Encode :
  2594. */
  2595. function cfExtDownload($completeFilename, $addressMode="relative"){
  2596.     $sep='.';
  2597.     if(substr($completeFilename,0,14)=='*resSpecific*/'){}
  2598.     else $completeFilename=rawurlencode(cfResourceRelativePath($completeFilename));
  2599.  
  2600.     // Generate tokenId
  2601.     $tokenId=''; for($i=0;$i<strlen($completeFilename);$i++) $tokenId.=ord($completeFilename[$i]);
  2602.     // Protect filename (apache rewrite URL regular expression used doesn't work with %2F...
  2603.     $completeFilename=str_replace('%2F','/',$completeFilename);
  2604.     // Base URI
  2605.     $uri='/dl/dlToken'.$tokenId.'/resId'.$_SESSION['activeResourceId'].'/';
  2606.  
  2607.     // Add filename
  2608.     $uri.=$completeFilename;
  2609.  
  2610.     if($addressMode=='relative') return $uri;
  2611.     if($addressMode=='absolute') return cfHostName().$uri;
  2612. }
  2613.  
  2614. /**
  2615.  * @desc generate "encoded" URL to a video file out of document root, using /ext/video.php
  2616.  * @return void
  2617.  * @param string $urlEncodedfileName
  2618.  * @param array $complement : extra information included in URL, to be used by ext/video.php:
  2619.  *             key values: q=>source, high, medium, low,
  2620.  *                         h=>height, w=>width,
  2621.  *                         image=>1 (if still image),
  2622.  *                         offset=>nbSeconds,
  2623.  *                         format=>wmv/flv/m3u8 (iPod, m3u8 file for given bitrate)/m3u8sa (iPod, m3u8 file pointing to bitrate-specific m3u8 files), ts (ipod streaming format (transport stream))
  2624.  *                         debug=>1
  2625.  * @param string $addressMode : $addressMode == "relative" : generate adress without host name,
  2626.                      $addressMode == "absolute" : generate adress with host name (used for files accessed by external programs (winamp, media player..., which don't have session cookie))
  2627.  * @param string $preUTF8Encode : true to utf8 encode complete filename, b64 to base64 encode, false not to encode
  2628. */
  2629. function cfExtVideo($completeFilename, $complement=array(), $addressMode="relative", $preUTF8Encode=true){
  2630.     $sep='.';
  2631.     if(!is_array($complement)) $complement=array();
  2632.     // replace # by *weezoSharp* (Media player problem with # symbol...)
  2633.     $completeFilename=str_replace('#', '*weezoSharp*',$completeFilename);
  2634.     // Special: if complete file name should be handled by resource (iTunes file ID), keep it unchanged
  2635.     if(substr($completeFilename,0,14)=='*resSpecific*/'){}
  2636.     // Special: if complete file name is music resource internal playlist (*playlist*.m3u[.xml]), keep it unchanged
  2637.     elseif($completeFilename=='*playlist*.m3u' || $completeFilename=='*playlist*.m3u.xml' || $completeFilename=='*singleMP3*.m3u' || $completeFilename=='*singleMP3*.m3u.xml' || $completeFilename=='*singleVideo*.xml') {
  2638.         // Opera cache problem workaround
  2639.         $complement+=array("rnd"=>str_pad(rand(),7,'X'));
  2640.     }
  2641.     elseif(cfIsSubDir(cfAppResourceDir(),$completeFilename) && cfRGetVar('resourceDataDirAccessAllowed')){
  2642.         $completeFilename=rawurlencode(cfUTF8Encode(cfResourceDataDirRelativePath($completeFilename)));
  2643.     }
  2644.     else {
  2645.         if($preUTF8Encode==='b64') $completeFilename=base64_encode(cfResourceRelativePath($completeFilename));
  2646.         elseif($preUTF8Encode) $completeFilename=rawurlencode(cfUTF8Encode(cfResourceRelativePath($completeFilename)));
  2647.         else $completeFilename=rawurlencode(cfResourceRelativePath($completeFilename));
  2648.     }
  2649.     $completeFilename=str_replace('%2F','/',$completeFilename);
  2650.     // Base URI
  2651.     $uri='/video/sess'.$sep.'sess_'.wSession_id().'/resId'.$sep.$_SESSION['activeResourceId'].'/';
  2652.     // Add extra parameters
  2653.     foreach ($complement as $k=>$v) /*if($k!='format')*/ $uri.=$k.$sep.$v.'/';
  2654.     // Add filename
  2655.     if(isset($complement['wmv'])) $completeFilename.=WMP_MOBILE_VIDEO_EXT;
  2656.  
  2657.     $uri.=(($preUTF8Encode==='b64' && $completeFilename[0]!='*')?'b64':'file').$sep.$completeFilename;
  2658.  
  2659.     if($addressMode=='relative') return $uri;
  2660.     if($addressMode=='absolute') return cfHostName().$uri;
  2661. }
  2662.  
  2663. /**
  2664.  * @desc generate "encoded" URL to an audio file out of document root, using /ext/audio.php
  2665.  * @return void
  2666.  * @param string $urlEncodedfileName
  2667.  * @param string $complement : extra information included in URL, to be used by /ext/audio.php (reencoded bitrate: /audio/original, /audio/64 ...)
  2668.  * @param string $addressMode : $addressMode == "relative" : generate adress without host name,
  2669.                      $addressMode == "absolute" : generate adress with host name (used for files accessed by external programs (winamp, media player...))
  2670.  * @param string $preUTF8Encode :
  2671. */
  2672. function cfExtAudio($completeFilename, $complement="", $addressMode="relative", $preUTF8Encode=true){
  2673.  
  2674.     // replace # by *weezoSharp* (Media player problem with # symbol...)
  2675.     $completeFilename=str_replace('#', '*weezoSharp*',$completeFilename);
  2676.     // Special : if complete file name should be handled by resource (iTunes file ID), keep it unchanged
  2677.     if(substr($completeFilename,0,14)=='*resSpecific*/'){}
  2678.     // Special : if complete file name is music resource internal playlist (*playlist*.m3u[.xml]), keep it unchanged
  2679.     elseif($completeFilename=='*playlist*.m3u' || $completeFilename=='*playlist*.m3u.xml' || $completeFilename=='*tmp*playlist*.m3u.xml' || $completeFilename=='*singleMP3*.m3u' || $completeFilename=='*singleMP3*.m3u.xml' || $completeFilename=='*singleVideo*.xml') {
  2680.         // Opera cache problem workaround
  2681.         $completeFilename="rnd".str_pad(rand(),7,'X').$completeFilename;
  2682.     }
  2683.     // File is located below resource data directory
  2684.     elseif(cfIsSubDir(cfAppResourceDir(),$completeFilename) && cfRGetVar('resourceDataDirAccessAllowed')){
  2685.         $completeFilename=rawurlencode(cfUTF8Encode(cfResourceDataDirRelativePath($completeFilename)));
  2686.     }
  2687.     // File is located below path
  2688.     else {
  2689.         if($preUTF8Encode) $completeFilename=rawurlencode(cfUTF8Encode(cfResourceRelativePath($completeFilename)));
  2690.         else $completeFilename=rawurlencode(cfResourceRelativePath($completeFilename));
  2691.     }
  2692.     $completeFilename=str_replace('%2F','/',$completeFilename); // Apache mod_rewrite doesn't seems to like %2F
  2693.  
  2694.     // Standalone WMP player (mobile), add WMP_MOBILE_AUDIO_EXT extension
  2695.     if(cfBGetVar('audioFormat')=='wma' || (cfBGetVar('wmp') && !cfBGetVar('flash'))) $completeFilename.=WMP_MOBILE_AUDIO_EXT;
  2696.  
  2697.     $rp='/audio/sess_'.wSession_id().'/resId'.$_SESSION['activeResourceId'].'/'.$complement.$completeFilename;
  2698.  
  2699.     if ($addressMode=='relative') return $rp;
  2700.     if ($addressMode=='absolute') return cfHostName().$rp;
  2701. }
  2702.  
  2703. /**
  2704.  * @desc return URL of image (out of document root) to use with extImage.php
  2705.  * @param string $completeFilename: path & file name of image, enclosed with "
  2706.  * @param int $width: max output width - non numeric value can be used for javascript search and replace
  2707.  * @param int $height: max output height - non numeric value can be used for javascript search and replace
  2708.  * @param boolean $cache: set to true to request caching from browser, false to prevent caching
  2709.  * @param integer $rotation: image rotation angle (degrees)
  2710.  * @param array $options: extra options array (icon=>1 to extract icon of file,'noDC'=>1 not to get audio cover from dir,'crop'=>1 to crop image to get a square)
  2711.  * @param array $rawFilename: set to true not to b64 encode filename (used to generate a javascript modifiable address)
  2712.  * @return string: URL
  2713. */
  2714. function cfExtImage($completeFilename,$width=false,$height=false, $cache=true, $rotation=0, $options=false, $rawFilename=false){
  2715.     $sep='.';
  2716.  
  2717.     /**
  2718.      * Get image src
  2719.      */
  2720.     // If image is (generated from) thumbnail
  2721.     if(cfIsSubDir(cfAppResourceDir(),$completeFilename)) $completeFilename=cfResourceDataDirRelativePath($completeFilename);
  2722.     // Shared files list
  2723.     elseif(cfSharedMode('list')) $completeFilename=cfResourceRelativePath($completeFilename);
  2724.     // Shared directory ?!?
  2725.     elseif (cfRGetVar('path') && cfIsSubDir(cfRGetVar('path'),$completeFilename)) $completeFilename=cfResourceRelativePath($completeFilename);
  2726.  
  2727.     $o='/img';
  2728.     // Width & height
  2729.     $o.='/w'.$sep.((is_numeric($width))?floor($width):$width).'/h'.$sep.((is_numeric($height))?floor($height):$height);
  2730.     // Rotation
  2731.     if($rotation) $o.='/rot'.$sep.$rotation; else $o.='/rot'.$sep.'0';
  2732.     // Browser cache
  2733.     if($cache) $o.='/cache'.$sep.'1'; else $o.='/cache'.$sep.'0';
  2734.     // Extra data
  2735.     if(is_array($options)) foreach ($options as $k=>$v) $o.='/'.$k.$sep.$v;
  2736.     // Resource id
  2737.     $o.='/resId'.$sep.$_SESSION['activeResourceId'];
  2738.     // dump filename (to be replaced by JS function
  2739.     if($rawFilename) $o.='/file.'.$completeFilename;
  2740.     // B64 encoded filename
  2741.     else $o.='/b64'.$sep.str_replace('/','*weezoSlash*',str_replace('+','*weezoPlus*',base64_encode($completeFilename))).'.'.cfFileExtension($completeFilename);
  2742.     return $o;
  2743. }
  2744.  
  2745. /**
  2746.  * return URL of resized image located into /www/gfx directory
  2747.  *
  2748.  * @param string $path: gfx path (ex: /gfx/icons/default.jpg)
  2749.  * @param int $width
  2750.  * @param int $height
  2751.  */
  2752. function cfExtGFX($path,$width,$height){
  2753.     $sep='.';
  2754.     if(substr($path,0,5)!='/gfx/') return;
  2755.     return '/img/w'.$sep.(floor($width)).'/h'.$sep.(floor($height)).'/rot'.$sep.'0/cache'.$sep.'1/resId'.$sep.'0/file'.$sep.$path;
  2756. }
  2757.  
  2758. /**
  2759.  * @desc Parse REQUEST_URI as used by /ext/... scripts:
  2760.  *         /property1.value1/property2.value2/property3.value3.../file/filename
  2761.  *
  2762.  * @return array if OK, false if format not OK;
  2763.  */
  2764. function cfParseExtURI(){
  2765.     $sep='.';
  2766.     $uri=stripcslashes(rawurldecode($_SERVER['REQUEST_URI']));
  2767.  
  2768.     if(!strpos($uri,'/file'.$sep) && !strpos($uri,'/b64'.$sep)) return false;
  2769.     $items=explode('/',substr($uri,1));
  2770.     //$items=explode('/',substr($uri,1,strpos($uri,'/file'.$sep)-1));
  2771.     $parsed=array();
  2772.     foreach ($items as $value) {
  2773.         if(strpos($value,$sep)) {
  2774.             list($k,$v)=explode($sep,$value,2);
  2775.             if($k=='file') break;
  2776.             if($k=='b64'){
  2777.                 if($k=='b64') $v=cfFileWithoutExtension($v);
  2778.                 if($k=='file') $v=cfUnprotectFilename($v);
  2779.                 else{$k='file';$v=base64_decode(str_replace('*weezoPlus*','+',str_replace('*weezoSlash*','/',$v)));}
  2780.                 $parsed[$k]=$v;
  2781.                 break;
  2782.             }
  2783.             $parsed[$k]=$v;
  2784.         }
  2785.         else $parsed[$value]=true;
  2786.     }
  2787.     if(!isset($parsed['file']))
  2788.         $parsed['file']=cfUnprotectFilename(substr($uri,strpos($uri,'/file'.$sep)+6));
  2789.  
  2790.     return $parsed;
  2791. }
  2792.  
  2793. /**
  2794.  * @return void
  2795.  * @param string $logString, string to log
  2796.  * @param string $logLevel, level of log (LOG_INF>LOG_DET>LOG_ER>LOG_DBG)
  2797.  * @desc log event to data/log/out.log.
  2798. */
  2799. function cfLog($logString, $logLevel, $dontLogToApp=false){
  2800.     $appLogLevel=-1;
  2801.     if(cfGGetVar('applicationLogDetail')=='non') $appLogLevel=LOG_NON;
  2802.     if(cfGGetVar('applicationLogDetail')=='inf') $appLogLevel=LOG_INF;
  2803.     if(cfGGetVar('applicationLogDetail')=='det') $appLogLevel=2;
  2804.     if(cfGGetVar('applicationLogDetail')=='dbg') $appLogLevel=LOG_DBG;
  2805.     // Send log to Weezo application
  2806.     if((!$dontLogToApp && !isset($_ENV['dontLogToApp'])) && $logLevel<=$appLogLevel)
  2807.         cfServerSendCmd('log',array('string'=>$logString,'logLevel'=>$logLevel));
  2808.  
  2809.     // Log to file
  2810.     $fileLogLevel=-1;
  2811.     if(cfGGetVar('fileLogDetail')=='non') $fileLogLevel=-1;
  2812.     if(cfGGetVar('fileLogDetail')=='inf') $fileLogLevel=0;
  2813.     if(cfGGetVar('fileLogDetail')=='det') $fileLogLevel=2;
  2814.     if(cfGGetVar('fileLogDetail')=='dbg') $fileLogLevel=3;
  2815.     if($logLevel<=$fileLogLevel){
  2816.         $logFileName=cfAppDataDir().'/log/phpScripts.log';
  2817.         // If file size exeed max allowed file size, archive file
  2818.         if(file_exists($logFileName) && cfGGetVar('fileLogMaxSize') && filesize($logFileName)>cfGGetVar('fileLogMaxSize')){
  2819.             @unlink($logFileName.'.old');
  2820.             rename($logFileName, $logFileName.'.old');
  2821.         }
  2822.         // Append to log file
  2823.         if(isset($_SERVER['REMOTE_ADDR'])) $ip=$_SERVER['REMOTE_ADDR']; else $ip='0.0.0.0';
  2824.         $logT='???'; if($logLevel==0) $logT='inf';if($logLevel==1) $logT='det';if($logLevel==2) $logT='err';if($logLevel==3) $logT='dbg';
  2825.     }
  2826. }
  2827.  
  2828.  
  2829. /**
  2830.  * @desc Return
  2831.  *
  2832.  * @param string $logOutput
  2833.  * @param integer $eventType: EVENT_CONNECTION, ... (see defines above)
  2834.  * @return mixed: array if $logOutput or $eventType set, boolean else
  2835.  */
  2836. function cfLogEventConfig($logOutput=false,$eventType=false){
  2837.     $logEventsConfig=@unserialize(cfGGetVar('logEventsConfig'));
  2838.     if(!$logOutput) return $logEventsConfig;
  2839.     if(!$eventType) return @$logEventsConfig[$logOutput];
  2840.     return @$logEventsConfig[$logOutput][$eventType];
  2841. }
  2842. /**
  2843.  * @desc Save logEvent config
  2844.  *
  2845.  * @param array $config
  2846.  */
  2847. function cfLogEventConfigSave($config){
  2848.     cfGUpdateVar('logEventsConfig',serialize($config));
  2849. }
  2850.  
  2851. /**
  2852.  * @desc Send event to differents log methods
  2853.  *
  2854.  * @param string $eventString: utf8 event description
  2855.  * @param integer $eventType: type of event
  2856.  * @param integer $eventSubType: subtype of event
  2857.  * @param string $eventExtraData: for user connections: id of group, for resource access: if of user/id of resource
  2858.  */
  2859. function cfLogEvent($eventString, $eventType, $eventSubType='',$eventExtraData=''){
  2860.     function cfLogEventCommand($logOutput,$eventString,$eventType,$eventSubType,$eventExtraData){
  2861.         cfPHPAsyncScript('/local/logOutputs/'.$logOutput.'.php?eventType='.$eventType.'&eventSubType='.$eventSubType.'&b64LogString='.urlencode(base64_encode($eventString)).'&b64ExtraData='.urlencode(base64_encode($eventExtraData)),(($eventType==EVENT_SERVERSTATE && $eventSubType==S_EVENT_OFF)?5000:50));
  2862.     }
  2863.  
  2864.     if(!is_array($logConfig=cfLogEventConfig())) return ;
  2865.  
  2866.     // Server state
  2867.     /*
  2868.     if($eventType==EVENT_SERVERSTATE){
  2869.         if($eventSubType==S_EVENT_LAN) $eventSubType=S_EVENT_OFF; // Don't display server as online when on LAN
  2870.         if(cfGGetVar('lastBroadcastedServerState')==$eventSubType) return; // Don't send twice
  2871.         cfGUpdateVar('lastBroadcastedServerState',$eventSubType);
  2872.     }
  2873.     */
  2874.  
  2875.     // Browse event receivers to find ones needing this one
  2876.     foreach ($logConfig as $logOutput=>$logOutputConfig) if(@$logOutputConfig[$eventType]){
  2877.         // Twitter: Add IP address to log string if requested by user configuration
  2878.         if($logOutput=='twitter' && $eventType==EVENT_SERVERSTATE && $eventSubType!==S_EVENT_OFF){
  2879.             require_once(INCLUDE_DIR.'/twitter.lib.php');
  2880.             @list($account,$password,$displayedIP)=twitterGetConnectionData();
  2881.             if($displayedIP) $eventString.=" (".cfExternalHostName().')';
  2882.         }
  2883.         // Async call log script
  2884.         cfLogEventCommand($logOutput,$eventString,$eventType,$eventSubType,$eventExtraData);
  2885.     }
  2886. }
  2887.  
  2888.  
  2889. /**
  2890.  * @desc Append text to file (debug purposes)
  2891.  *
  2892.  * @param string $text : text to write
  2893.  * @param string $completeFilename : path and file name of file, set to "1" to display in a msgbox
  2894.  * @return true if success, false if file couldn't be opened
  2895.  */
  2896. function cfAppendTextToFile($text, $completeFilename=false,$prependTime=true){
  2897.     if(!$completeFilename) $completeFilename=cfAppDataRootDir().'/log.txt';
  2898.     elseif ($completeFilename==1||$completeFilename==2) $prependTime=false;
  2899.  
  2900.     if($completeFilename!=1 && $completeFilename!=2 && !($handle=@fopen($completeFilename,'a'))) return false;
  2901.  
  2902.     if(is_array($text)){
  2903.         if($prependTime) $out=date('H:i:s')."\n"; else $out='';
  2904.         foreach ($text as $key=>$value) {
  2905.             if($value===true) $value='TRUE'; elseif($value===false) $value='FALSE';
  2906.             $out.=$key.'='.((is_array($value))?'Array ('.count($value).')':((is_object($value))?'Object':$value))."\n";
  2907.             if(is_array($value)){
  2908.                 foreach ($value as $key2=>$value2) {
  2909.                     if($value2===true) $value2='TRUE'; elseif($value2===false) $value2='FALSE';
  2910.                     $out.=chr(9).$key2.'='.((is_array($value2))?'Array ('.count($value2).')':((is_object($value2))?'Object':$value2))."\n";
  2911.                 }
  2912.             }
  2913.         }
  2914.     }
  2915.     else {
  2916.         if($prependTime) {
  2917.             $ms=microtime(true); $ms=floor(1000*($ms-floor($ms)));
  2918.             $out=date('H:i:s').'.'.$ms.'>';
  2919.         }
  2920.         else $out='';
  2921.         if($text===true) $out.='TRUE';
  2922.         elseif($text===false) $out.='FALSE';
  2923.         else $out.=$text;
  2924.     }
  2925.     if($completeFilename==1) customMsgbox($out);
  2926.     elseif($completeFilename==2) {
  2927.         cfExecNoFork(cfAppBinDir().'/Dbg.exe','SW_SHOW_NORMAL',str_replace("\r",'\\r',str_replace("\n",'\\n',str_replace("\r\n",'\n',$out))));
  2928.         //exec(cfAppBinDir().'/Dbg.exe '.str_replace("\r",'\\r',str_replace("\n",'\\n',str_replace("\r\n",'\n',$out))));
  2929.     }
  2930.     else{
  2931.         fwrite($handle,$out."\n");
  2932.         fclose($handle); return true;
  2933.     }
  2934. }
  2935.  
  2936. /**
  2937.  * @desc Debug to msgbox, php output or /log.txt text file
  2938.  *
  2939.  * @param string $text : text to output
  2940.  * @param string $completeFilename : filename of output, or false for /log.txt or 0 for output, or 1 for message box
  2941.  * @param boolean $prependTime : set to true to prepend time to text (file only)
  2942.  */
  2943. function cfDbg($text=null, $completeFilename=2,$prependTime=false){ // prod
  2944.     if(isset($_ENV['noDebug'])) return;
  2945.     if($text===null) {$completeFilename=1;$txt=__FILE__.'/'.__FUNCTION__.'/'.__LINE__;}
  2946.     if(is_numeric($completeFilename)) $prependTime=false;
  2947.     if($completeFilename===0) cfVarDump($text); // prod
  2948.     else cfAppendTextToFile($text,$completeFilename,$prependTime);
  2949. }
  2950.  
  2951. /**
  2952.  * @desc Display ascii values of chars
  2953.  *
  2954.  * @param string $txt
  2955.  * @return string
  2956.  */
  2957. function cfDbgTxt($txt,$asciiOnly=1){$output='';    for($i=0;$i<strlen($txt);$i++) $output.=ord($txt[$i]).(($asciiOnly)?' ':'('.$txt[$i].') '); return $output;} // prod
  2958.  
  2959. /**
  2960.  * @return void
  2961.  * @param mixed array $var : var to dump
  2962.  * @desc "HTML visual" version of var_dump
  2963. */
  2964. function cfVarDump($var){ // prod
  2965.     echo "\n<pre>\n";
  2966.     var_dump($var);
  2967.     echo "</pre>\n";
  2968. }
  2969.  
  2970. /**
  2971.  * @desc Set input/output info into debug buffer. See /pub/debugAsync for details
  2972.  *
  2973.  * @param string $type ('async','image','audio'...)
  2974.  * @param array $req: request arguments ($_POST...)
  2975.  * @param string $resp: response output
  2976.  */
  2977. function cfDebugSetBuffer($type,$req,$resp='...'){
  2978.     if($_SERVER['SCRIPT_NAME']=='/pub/debugAsync.php') return;
  2979.     $buff=cfMGetVar('debugAsyncBuffer');
  2980.     if(!is_array($buff)) $buff=array();
  2981.     if(!is_array($req)) $req=array('?'=>$req);
  2982.  
  2983.     // Add buffer updates sent before cfDebugSetBuffer call
  2984.     if(isset($_ENV['debugAsyncExtraBuffer']) && is_array($_ENV['debugAsyncExtraBuffer'])) {
  2985.         foreach ($_ENV['debugAsyncExtraBuffer'] as $k=>$v){
  2986.             $resp.="\n".$k.'='.$v;
  2987.         }
  2988.     }
  2989.  
  2990.     $buff[]=array($type,
  2991.         array('SCRIPT'=>$_SERVER['REQUEST_URI'])+$req,
  2992.         $resp,
  2993.         array('UA'=>@$_SERVER['HTTP_USER_AGENT'])+getallheaders(),
  2994.         headers_list(),
  2995.         array($_ENV['chrono'][0]['time'],microtime(true)));
  2996.     cfMSetVar('debugAsyncBuffer',$buff);
  2997.     $_ENV['debugAsyncBufferSet']=1;
  2998. }
  2999.  
  3000. /**
  3001.  * @desc Update debug buffer with script output
  3002.  *
  3003.  * @param string $resp: string to be sent to debug output
  3004.  * @param bool $concatenate: true to concatenate instead of replace
  3005.  */
  3006. function cfDebugUpdateBuffer($resp,$concatenate=1){
  3007.     if(!cfMGetVar('debugAsync')) return ;
  3008.     if(!isset($_ENV['debugAsyncBufferSet'])){
  3009.         if(!isset($_ENV['debugAsyncExtraBuffer'])) $_ENV['debugAsyncExtraBuffer']=array();
  3010.         if(!is_array($resp)) $resp=array('?'=>$resp);
  3011.         $_ENV['debugAsyncExtraBuffer']=$_ENV['debugAsyncExtraBuffer']+$resp;
  3012.         return;
  3013.     }
  3014.     $buff=cfMGetVar('debugAsyncBuffer');
  3015.     if(!is_array($buff)) $buff=array();
  3016.     if(is_array($resp)){
  3017.         $tmp='';
  3018.         foreach ($resp as $k=>$b) $tmp.=$k.'='.(($v)?''+$v:(($v===0)?'0':"VOID"))."\n";
  3019.         $resp=$tmp;
  3020.     }
  3021.     $buff[]=array($_ENV['chrono'][0]['time'],(($concatenate)?'+':'=').$resp,microtime(true),headers_list());
  3022.     cfMSetVar('debugAsyncBuffer',$buff);
  3023. }
  3024.  
  3025. /**
  3026.  * @desc Set input/output info into debug buffer. See /pub/debugAsync for details
  3027.  *
  3028.  * @param mixed $mixed: data sent to debug (string or array)
  3029.  */
  3030. function cfDebugSingle($mixed='...'){
  3031.     if(!cfMGetVar('debugAsync') || substr($_SERVER['REQUEST_URI'],0,19)=='/pub/debugAsync.php') return;
  3032.     $buff=cfMGetVar('debugAsyncBuffer'); if(!is_array($buff)) $buff=array();
  3033.     $buff[]=array(str_replace(array("\r","\n"),'',$mixed));
  3034.     cfMSetVar('debugAsyncBuffer',$buff);
  3035. }
  3036.  
  3037. /**
  3038.  * @desc Start output buffering for responding to a (potential) HTTP Range request
  3039.  *
  3040.  */
  3041. function cfRangeAccessibleOutputStart(){ob_start();}
  3042.  
  3043. /**
  3044.  * @desc Send header and output for (potential) HTTP Range request.
  3045.  *             cfRangeAccessibleOutputStart() must have been called before output start
  3046.  *
  3047.  */
  3048. function cfRangeAccessibleOutputSend(){
  3049.     $buff=ob_get_clean();
  3050.  
  3051.     $h=getallheaders();
  3052.     // No range required: just send output
  3053.     if(!isset($h['Range'])) {
  3054.         header('Content-Length: '.strlen($buff));
  3055.         header("Accept-Ranges: bytes");
  3056.         echo $buff;
  3057.         return;
  3058.     }
  3059.  
  3060.     // Range required: parse request and send only requested range
  3061.     header('HTTP/1.1 206 Partial Content');
  3062.     $h['Range']=substr($h['Range'],6);
  3063.     list($from,$to)=explode('-',$h['Range']);
  3064.     header("Content-Range: bytes $from-$to/".strlen($buff));
  3065.     header("Content-Length: ".(1+$to-$from));
  3066.     header("Accept-Ranges: bytes");
  3067.  
  3068.     echo substr($buff,$from,1+$to-$from);
  3069. }
  3070.  
  3071. /**
  3072.  * @return boolean : true if success, false if user file couldn't be opened
  3073.  * @param string $completeFilename : path & file name of file to download / stream
  3074.  * @param int $isTransfer : set download as (monitored) transfer
  3075.  * @param int $speedLimit : max download speed (kBytes per second)
  3076.  * @desc stream file to output (no header sent)
  3077. */
  3078. function cfStreamFile($completeFilename, $isTransfer=false, $speedLimit = 0, $range=false){
  3079.     $bufferSize=32768*16;
  3080.  
  3081.     wSession_write_close(); unset($_SESSION);
  3082.     if(!isset($_ENV['cfStreamFileNoLog'])) cfLog('cfStream file : '.$completeFilename,LOG_DBG);
  3083.     if(!file_exists($completeFilename)) return false;
  3084.     if(!($handle = @fopen ($completeFilename, "rb"))) return false;
  3085.     set_time_limit(0);
  3086.     // no dowload monitoring and no speed limit : send file to output
  3087.     if($speedLimit==0 && !$isTransfer && !$range) {
  3088.         while (!feof($handle)) {
  3089.             echo(fread($handle, $bufferSize)); flush();
  3090.             cfPingUpdate(30);// Ping app
  3091.         }
  3092.     }
  3093.     // else
  3094.     else{
  3095.         require_once(INCLUDE_DIR.'transferFunctions.php');
  3096.         // Monitor download as transfer
  3097.         $fileSize=cfFileSize($completeFilename);
  3098.         if($isTransfer){
  3099.             $t=tAddDownload($completeFilename);
  3100.             $lastRefresh=time();
  3101.         }
  3102.         $speedLimit*=1024;
  3103.         if($speedLimit) {
  3104.             $bufferSize=min($bufferSize,$speedLimit);
  3105.             // Set-up transfer speed limitation
  3106.             $limit=new transferLimitation($speedLimit);
  3107.         }
  3108.  
  3109.         $transferedSize=0;
  3110.  
  3111.         // Set range
  3112.         if(isset($range['from'])) {$pos=$range['from'];fseek($handle,$pos);} else $pos=0;
  3113.         if(isset($range['to'])) $to=$range['to']; else $to=$fileSize;
  3114.  
  3115.         // Stream file
  3116.         while (!feof($handle) && $pos<$to && (!$isTransfer || ($t->exists() && $t->status!=9))) { // (stop streaming if transfer status is 9 = "stoped")
  3117.             cfPingUpdate(30);// Ping app
  3118.             if($pos+$bufferSize>$to) $bufferSize=$to-$pos;
  3119.  
  3120.              echo fread($handle, $bufferSize); flush();
  3121.              $transferedSize+=$bufferSize;
  3122.              $pos+=$bufferSize;
  3123.  
  3124.             // Download monitoring
  3125.             if($isTransfer && (time()-$lastRefresh)>=$t->updateInterval && $fileSize>0){
  3126.                 // Transfert stopped : quit
  3127.                 if(!$t->exists() || $t->status==9) break;
  3128.                 // Update transfert progress
  3129.                 $t->updateProgress($transferedSize/$fileSize,true);
  3130.                 $t->commitToFile(false,false);
  3131.  
  3132.                 $lastRefresh=time();
  3133.             }
  3134.             // Speed limitation
  3135.              if($speedLimit) $limit->addData($bufferSize);
  3136.         }
  3137.         // Download monitoring : set upload complete
  3138.         if($isTransfer) {$t->updateProgress(1,false);$t->updateStatus(4,true);}
  3139.         if($speedLimit) unset($limit);
  3140.     }
  3141.     fclose($handle);
  3142.  
  3143.     //if(!$isTransfer || $t->status!=9) cfLog('Download of : '.$completeFilename.' completed',LOG_DBG);
  3144.     return  true;
  3145. }
  3146.  
  3147. /**
  3148.  * @desc stream string to output applying speed limitation
  3149.  *
  3150.  * @param string $string: string to stream
  3151.  * @param integer $speedLimit: speed limitation (kBytes per second), false to use user's
  3152.  */
  3153. function cfStreamString(&$string, $speedLimit=false){
  3154.     // If speed limit not set, set user speed limit
  3155.     if($speedLimit===false) $speedLimit=cfUGetVar('downloadSpeedLimit');
  3156.     // No speed limit : output string
  3157.     if(!$speedLimit) echo $string;
  3158.     else{
  3159.         $speedLimit*=1024; // Set limit in B/s
  3160.         $bufferSize=$speedLimit; // Set buffer size
  3161.         $pos=0;    $l=strlen($string);
  3162.         require_once(INCLUDE_DIR.'transferFunctions.php');
  3163.         $limit=new transferLimitation($speedLimit);
  3164.         do{
  3165.             echo substr($string,$pos,$bufferSize);
  3166.             $limit->addData($bufferSize);
  3167.             $pos+=$bufferSize;
  3168.         } while ($pos<$l);
  3169.     }
  3170. }
  3171.  
  3172. /**
  3173.  * @desc stream stdout or stderr of a process to php output, or return it as function's return
  3174.  *         kill process if user aborts
  3175.  *
  3176.  * @param string $commandLine: full path/exe args command line
  3177.  * @param array $std: keys: 'stdout' and/or 'stderr'. See $outputProcess for values
  3178.  * @param string $outputProcess (optional, use only if $std is a string (backward compatibility)):
  3179.  *             'stdout' to send proc output to stdout,
  3180.  *             'return' to return as function's return
  3181.  *             false to discard
  3182.  *             function name : named function is called at every stream cycle
  3183.  * @param array $extraOptions: other options
  3184.  *             'bufferSize'=>bufferSize: set buffer size, in bytes
  3185.  *             'speedLimit'=>speed limitation, max download speed (kBytes per second)
  3186.  *             'haltOnSeq'=>string that will halt streaming if found at end of buffer (workaround to hanging in some case...)
  3187.  *             'writeStdin'=>string that will be sent to in pipe
  3188.  *            'ignoreConnectionAbort': set to indicate that function should return even if connection aborted
  3189.  *            'range': array('from'=>, 'to'=>) : only output bytes from/to
  3190.  *
  3191.  * @return mixed: string result if $outputProcess=='return', else void
  3192.  */
  3193. function cfStreamProc($commandLine, $std=array('stdout'=>false), $extraOptions=array(),&$streamedLength=-1){
  3194.     $getTotal=($streamedLength===-1)?0:1;
  3195.     $streamedLength=0;
  3196.     // Range processing
  3197.     if($range=@$extraOptions['range']){$from=$range['from'];$to=$range['to'];}
  3198.  
  3199.     $bufferSize=32384; // Higher values will likely result in system hang
  3200.     $bufferSize=8196; // Higher values will likely result in system hang
  3201.  
  3202.     // Close session if started (as cfStreamProc might in some cases hang, doesn't block user...)
  3203.     if(cfSessionIsStarted()) {
  3204.         // Mem active resource so it's not "hijacked" by another resource during streaming
  3205.         if(isset($_SESSION['activeResourceId'])) $activeResourceId=$_SESSION['activeResourceId'];
  3206.  
  3207.         wSession_write_close();
  3208.         $restartSession=1;
  3209.     }
  3210.  
  3211.     // Backward compatibility
  3212.     if(!is_array($std)) $std=array($std=>$outputProcess);
  3213.  
  3214.     if(!isset($std['stdout']) && !isset($std['stderr'])) {
  3215.         trigger_error('cfStreamProc: wrong $std parameter, must be "stdout" or "stderr"',E_ERROR);
  3216.         return;
  3217.     }
  3218.  
  3219.     // Clean command line
  3220.     $commandLine=trim($commandLine);
  3221.     if($commandLine[0]=='"') {
  3222.         $fullPath=substr($commandLine,1,strpos($commandLine,'"',1)-1);
  3223.         $args=substr($commandLine,strpos($commandLine,'"',1)+1);
  3224.     }
  3225.     else{
  3226.         $fullPath=substr($commandLine,0,strpos($commandLine,' ',1));
  3227.         $args=substr($commandLine,strpos($commandLine,' ',1));
  3228.     }
  3229.     $commandLine='"'.str_replace('\\','/',$fullPath).'"'.$args;
  3230.  
  3231.     // Set-up transfer speed limitation
  3232.     if(isset($extraOptions['speedLimit'])) $speedLimit=$extraOptions['speedLimit']; else $speedLimit=0;
  3233.     if($speedLimit) {
  3234.         $speedLimit*=1024;
  3235.         $bufferSize=min($bufferSize,$speedLimit);
  3236.         require(INCLUDE_DIR.'transferFunctions.php');
  3237.         $limit=new transferLimitation($speedLimit);
  3238.     }
  3239.  
  3240.     // Force buffer size
  3241.     if(isset($extraOptions['bufferSize'])) $bufferSize=$extraOptions['bufferSize'];
  3242.  
  3243.     // Stop on given char at end of buffer (used as a workaround to random blocking on fread)
  3244.     if(isset($extraOptions['haltOnSeq'])) $haltOnSeq=$extraOptions['haltOnSeq'];
  3245.  
  3246.     $transferedSize=0;    $buffer='';
  3247.  
  3248.     $desc= array(0 => array("pipe", "r"), 1 => array("pipe", "w"),  2 => array("pipe", "w"));
  3249.  
  3250.     // Open process
  3251.     $process=@proc_open($commandLine, $desc, $pipes, getcwd(), null, array('binary_pipes'=>TRUE,'bypass_shell'=>TRUE));
  3252.     $noCmd=true; // Indicate that process is not run with an extra CMD window
  3253.     if(!$process){
  3254.         $process=@proc_open($commandLine, $desc, $pipes, getcwd(), null, array('binary_pipes'=>TRUE));
  3255.         $noCmd=false;
  3256.         if(!$process){
  3257.             trigger_error('cfStreamProc: cannot open process',E_USER_WARNING);
  3258.             return;
  3259.         }
  3260.     }
  3261.  
  3262.     set_time_limit(0);
  3263.     ignore_user_abort(1);
  3264.  
  3265.     // Write in stdin
  3266.     if(isset($extraOptions['writeStdin'])) fwrite($pipes[0],$extraOptions['writeStdin']);
  3267.  
  3268.     /**
  3269.      * Close unused pipes
  3270.      */
  3271.  
  3272.     // Close stdin
  3273.     if(!isset($std['stdin'])) fclose($pipes[0]);
  3274.     // Close stderr
  3275.     if(!isset($std['stderr'])) fclose($pipes[2]);
  3276.     // Close stdout
  3277.     if(!isset($std['stdout'])) fclose($pipes[1]);
  3278.  
  3279.     /********************************
  3280.      * STREAM STDOUT and/or STDERR (start by stdout)
  3281.      ********************************/
  3282.     while(isset($std['stdout'])||isset($std['stderr'])){
  3283.         // Select stdout/stderr pipe
  3284.         if(isset($std['stdout'])) {
  3285.             $pipe=$pipes[1];
  3286.             $outputProcess=$std['stdout'];
  3287.         }
  3288.         else {
  3289.             $pipe=$pipes[2];
  3290.             $outputProcess=$std['stderr'];
  3291.         }
  3292.         stream_set_blocking($pipe, 0);
  3293. $pid=rand();
  3294.         while (!feof($pipe)) {
  3295.             if(connection_aborted() && !isset($extraOptions['ignoreConnectionAbort'])) break(2);
  3296.             // Read pipe
  3297.             $buff=fread($pipe, $bufferSize);
  3298.             if($getTotal||$range) $streamedLength+=($bl=strlen($buff));
  3299.  
  3300.             // Range slicing
  3301.             if($range){
  3302.                 if($streamedLength<=$from) $buff='';
  3303.                 elseif ($streamedLength>$from && $streamedLength-$bl<$from) $buff=substr($buff,$from+$bl-$streamedLength);
  3304.                 elseif ($streamedLength>$to && $streamedLength-$bl<=$to) $buff=substr($buff,0,$to+$bl-$streamedLength);
  3305.                 elseif ($streamedLength>$to) {$buff=''; break;}
  3306.             }
  3307.  
  3308.             // flush data to output
  3309.             if($outputProcess=='stdout') {echo $buff; flush();}
  3310.             // concatenate to buffer
  3311.             elseif($outputProcess=='return') $buffer.=$buff;
  3312.             // Callback function (exit if callback function returns true)
  3313.             elseif($outputProcess!==false){
  3314.                 if(call_user_func($outputProcess,$buff)===true) break(2);
  3315.             }
  3316.  
  3317.             // Speed limitation
  3318.             if($speedLimit) $limit->addData(strlen($buff));
  3319.             // Ping app
  3320.             cfPingUpdate(3);
  3321.  
  3322.             usleep(1000);
  3323.  
  3324.             if(isset($haltOnSeq) && substr($buff,-strlen($haltOnSeq))==$haltOnSeq) break(2);
  3325.             if(connection_aborted() && !isset($extraOptions['ignoreConnectionAbort'])) break(2);
  3326.         }
  3327.  
  3328.         if($pipe==$pipes[1]) unset($std['stdout']); else unset($std['stderr']);
  3329.         fclose($pipe);
  3330.     }
  3331.     // if "break(2)" exit
  3332.     @fclose($pipe);
  3333.  
  3334.     if($speedLimit) unset($limit);
  3335.  
  3336.     $status=proc_get_status($process);
  3337.  
  3338.     // Kill process if not not terminated
  3339.     if(is_array($status) && $status['running']) {
  3340.         // Always use Kill method as proc_terminate seems to hang sometimes...
  3341.         if(0 && $noCmd) proc_terminate($process);// Terminate process
  3342.         else customTerminateProcess($status['pid']);// Terminate cmd process and it's children
  3343.         usleep(5000);
  3344.     }
  3345.  
  3346.     // Close process
  3347.     proc_close($process);
  3348.  
  3349.  
  3350.     // Reset settings
  3351.     set_time_limit(ini_get('max_execution_time'));
  3352.     if(!isset($extraOptions['ignoreConnectionAbort'])) ignore_user_abort(0);
  3353.  
  3354.     // Restart session if needed
  3355.     if(isset($restartSession)) {
  3356.         wSession_start();
  3357.         if(isset($activeResourceId)) $_SESSION['activeResourceId']=$activeResourceId;
  3358.     }
  3359.  
  3360.     if($outputProcess=='return') return $buffer;
  3361.     if($outputProcess && $outputProcess!='stdout') call_user_func($outputProcess,null);
  3362. }
  3363.  
  3364. /**
  3365.  * @desc Execute a process and wait till it has returned
  3366.  *
  3367.  * @param string $exeCompleteFilename: complete filename of file to execute
  3368.  * @param string $mode: 'SW_MINIMIZE', 'SW_HIDE', 'SW_SHOWNORMAL', 'SW_SHOWMINNOACTIVE', 'SW_SHOWDEFAULT'
  3369.  * @param string $commandLine: arguments
  3370.  * @param string $maxExecutionTime: maximum exection time, in seconds
  3371.  * @return boolean: true if function executed
  3372.  */
  3373. function cfExecNoFork($exeCompleteFilename,$mode='SW_SHOW_NORMAL',$commandLine='',$maxExecutionTime=0){
  3374.     return customExecNoFork($exeCompleteFilename,$mode,$commandLine,$maxExecutionTime);
  3375. }
  3376.  
  3377. /**
  3378.  * @desc Execute a process but don't wait till it has returned
  3379.  *
  3380.  * @param string $exeCompleteFilename: complete filename of file to execute
  3381.  * @param string $mode: 'SW_SHOWNORMAL', 'SW_HIDE'
  3382.  * @param string $commandLine: arguments
  3383.  * @param boolean $idle: set to true to run idle, 0 to run with normal priority
  3384.  * @return boolean: true if function executed
  3385.  */
  3386. function cfExecFork($exeCompleteFilename,$mode='SW_SHOW_NORMAL',$commandLine='',$idle=1){
  3387.     return customExecFork($exeCompleteFilename,$mode,$commandLine,$idle);
  3388. }
  3389.  
  3390. /**
  3391.  * @desc Async Exec a script on server. This script must ignore user abort and should not open session
  3392.  *
  3393.  * @param string $URL
  3394.  * @param integer $maxWait : set this parameter to wait script's end if less than $maxWait ms AFTER SOCKET CONNECTION
  3395.  */
  3396. function cfPHPAsyncScript($URI,$maxWait=50){
  3397.     if($host=cfLocalhostName()){
  3398.         $fp=cfSocketHTTPRequest($host.$URI,4,false,$foo,$foo,false,true);
  3399.         if(!$fp) return false;
  3400.  
  3401.         $t=0;
  3402.         while ($t<1000*$maxWait && !feof($fp)) {
  3403.              //fread($fp,8162);
  3404.              usleep(10000);
  3405.              $t+=10000;
  3406.         }
  3407.         usleep(50000);
  3408.         fclose($fp);
  3409.     }
  3410.     else {
  3411.         if(strpos($URI,'?')){
  3412.             list($URI,$get)=explode('?',$URI,2);
  3413.             parse_str($get,$_GET);
  3414.         }
  3415.         require(cfAppDocRoot().$URI);
  3416.     }
  3417. }
  3418.  
  3419. /**
  3420.  * @return string : truncated string
  3421.  * @param string $str : string to truncate
  3422.  * @param int maxLen : max len of output string
  3423.  * @desc return input string if len<maxLen, or truncated string, ended by '...' if len>=maxLen
  3424. */
  3425. function cfStrTruncate($str, $maxLen=0){
  3426.     if($maxLen==0) return $str;
  3427.     if(strlen($str) <= $maxLen) return $str;
  3428.     return substr($str,0,$maxLen-3).'...';
  3429. }
  3430.  
  3431. /**
  3432.  * @desc put values as keys
  3433.  *
  3434.  * @param array $in
  3435.  * @return array
  3436.  */
  3437. function cfArrayValuesToKeys($in){
  3438.     if(!is_array($in)) return array($in=>$in);
  3439.     $out=array();
  3440.     foreach ($in as $k=>$v) if(is_numeric($k)) $out[$v]=$v; else $out[$k]=$v;
  3441.     return $out;
  3442. }
  3443. /**
  3444.  * @desc Exchange keys and valued
  3445.  *
  3446.  * @param array $in
  3447.  * @return array
  3448.  */
  3449. function cfArraySwapKeysValues($in){
  3450.     foreach ($in as $k=>$v) $out[$v]=$k;
  3451.     return $out;
  3452. }
  3453. /**
  3454.  * @return array : result of parsing
  3455.  * @param : string $completeFilename : path and file name of file to parse
  3456.  * @param : bool $process_sections : if set to true, sections are passed as sub arrays
  3457.  * @param : bool $$verifyVariableName : if set to true, key format is checked with validVariableName() function
  3458.  * @desc equivalent to parse_ini_file, but doesn't need to put "" around non alpha-numeric data
  3459. */
  3460. function cfParse_ini_file($completeFilename,$process_sections=true, $verifyVariableName=true){
  3461.     if(!file_exists($completeFilename) || !is_readable($completeFilename)) return false;
  3462.     if(!($handle = @fopen($completeFilename, 'r'))) return false;
  3463.     $parsed=array();
  3464.     $sectionName=false;
  3465.     $element=array();
  3466.     while (!feof($handle)) {
  3467.         $line=trim(fgets($handle));
  3468.         if(substr($line,0,1)!=';' && substr($line,0,1)!='#'){
  3469.             if(substr($line,0,1)=='[' && substr($line,-1)==']' && (!$verifyVariableName || validVariableName(trim(substr($line,1,strlen($line)-2))))){
  3470.                 if($sectionName!==false && count($element)){
  3471.                     $parsed[$sectionName]=$element;
  3472.                     unset($element);$element=array();
  3473.                 }
  3474.                 $sectionName=substr($line,1,strlen($line)-2);
  3475.             }
  3476.             else{
  3477.                 if($pos=strpos($line,'=')){
  3478.                     $key=trim(substr($line,0,$pos));
  3479.                     $value=trim(substr($line,$pos+1));
  3480.                     if(strtolower($value)==='false') $value=false;
  3481.                     elseif(strtolower($value)==='true') $value=true;
  3482.                     elseif($value==='0') $value=0;
  3483.                     elseif($value==='1') $value=1;
  3484.                     if((!$verifyVariableName) || validVariableName($key)){
  3485.                         if(!$process_sections || !$sectionName) $parsed[$key]=$value; else $element[$key]=$value;
  3486.                     }
  3487.                 }
  3488.             }
  3489.         }
  3490.     }
  3491.     if($sectionName!==false && count($element)){
  3492.         $parsed[$sectionName]=$element;
  3493.     }
  3494.     fclose($handle);
  3495.     unset($element);
  3496.     return $parsed;
  3497. }
  3498. function validVariableName($variable) {return (ereg("^([a-zA-Z0-9]|@|_)+$", $variable));}
  3499.  
  3500. /**
  3501.  * @return boolean : true if success, false if user file couldn't be written
  3502.  * @param mixed array $params : arg / value array to write
  3503.  * @param string $includeWarning : if true, include a commented "Automaticaly generated file" warning message at begining of file
  3504.  * @param string $completeFilename : file name.
  3505.  * @desc Write ini file (arg=value), from $params array of parameters
  3506. */
  3507. function cfWriteIniFile($params, $completeFilename=false,$includeWarning=true){
  3508.     if(!($handle= fopen($completeFilename,'w'))) return false;
  3509.     if($includeWarning) fwrite($handle, "; Automaticaly generated file\n; Manual modifications might (or might not) be erased...\n;\n");
  3510.     foreach ($params as $key => $value){
  3511.         if(!is_array($value)){
  3512.             if($value===true) fwrite($handle,$key." = true\n");
  3513.             elseif($value===false) fwrite($handle,$key." = false\n");
  3514.             else fwrite($handle,$key.' = '.str_replace("\n","\r",$value)."\n");
  3515.         }
  3516.     }
  3517.     foreach ($params as $key => $value){
  3518.         if(is_array($value)){
  3519.             fwrite($handle,"\n".'['.$key.']'."\n");
  3520.             foreach ($value as $key2 => $value2){
  3521.                 if($value2===true) fwrite($handle,$key2." = true\n");
  3522.                 elseif($value2===false) fwrite($handle,$key2." = false\n");
  3523.                 else fwrite($handle,$key2.' = '.str_replace("\n",'',$value2)."\n");
  3524.             }
  3525.         }
  3526.     }
  3527.     fclose($handle);
  3528.     return true;
  3529. }
  3530.  
  3531. /**
  3532.  * @return string : browser name
  3533.  * @desc return browser description (name) baset on HTTP_USER_AGENT
  3534. */
  3535. function cfGetBrowser(){
  3536.     if(isset($_ENV['cfGetBrowserResult'])) return $_ENV['cfGetBrowserResult'];
  3537.     if(!isset($_SERVER['HTTP_USER_AGENT'])) return false; else $ua=strtolower($_SERVER['HTTP_USER_AGENT']);
  3538.     if(strpos($ua, "opera")!==false) $_ENV['cfGetBrowserResult']='opera';
  3539.     elseif(strpos(($ua), "webkit")!==false)  $_ENV['cfGetBrowserResult']='webkit';
  3540.     elseif(strpos(($ua), "gecko")!==false) $_ENV['cfGetBrowserResult']='gecko';
  3541.     elseif(strpos(($ua), "msie")!==false)  $_ENV['cfGetBrowserResult']='ie';
  3542.     else $_ENV['cfGetBrowserResult']='other';
  3543.     return $_ENV['cfGetBrowserResult'];
  3544. }
  3545. /**
  3546.  * @desc return first language supported by Browser and Weezo
  3547.  *
  3548.  * @return string : ISO (2 letters) language code
  3549.  */
  3550. function cfGetBrowserLng(){
  3551.     if(!count($l = split(",", $_SERVER['HTTP_ACCEPT_LANGUAGE']))) return 'en';
  3552.     foreach ($l as $lng){
  3553.         if(file_exists(cfAppDocRoot().'/includes/lng/'.substr($lng,0,2).'.php')) return substr($lng,0,2);
  3554.     }
  3555.     return 'en';
  3556.  
  3557. }
  3558.  
  3559. /**
  3560.  * @return void
  3561.  * @desc Add "chrono point"
  3562.  * @param string label : label of chrono point
  3563. */
  3564. function cfChronoAddPoint($label=false){
  3565.     static $lb;
  3566.     if(!$label) $label='point:'.@$lb++;
  3567.     if(!isset($_ENV['chrono'])) $_ENV['chrono']=array();
  3568.     $_ENV['chrono'][count($_ENV['chrono'])]['label']=$label;
  3569.     $_ENV['chrono'][count($_ENV['chrono'])-1]['time']=microtime(true);
  3570. }
  3571. function cfChronoFormat($delta){
  3572.     if($delta>1) return (floor(1000*$delta)/1000).'s'; elseif($delta>0.001) return floor($delta*1000).'ms';else return floor($delta*1000000).'╡s';
  3573.     return $output;
  3574. }
  3575.  
  3576. /**
  3577.  * @desc start ot stop "interval" execution time computing
  3578.  *
  3579.  * @param srting $label : interval label
  3580.  * @param string $action : 's' to indicate than chrono must start at this point, 'e' to indicate than chrono must stop at this point
  3581.  */
  3582. function cfChronoInt($label,$action){
  3583.     if(!isset($_ENV['chronoInt']['int'][$label])) $_ENV['chronoInt']['int'][$label]=array('time'=>0,'nb'=>0);
  3584.     if($action=='s') $_ENV['chronoInt']['tmp'][$label]=microtime(true);
  3585.     if($action=='e'){
  3586.         $_ENV['chronoInt']['int'][$label]['time']+=microtime(true)-$_ENV['chronoInt']['tmp'][$label];
  3587.         $_ENV['chronoInt']['int'][$label]['nb']++;
  3588.     }
  3589. }
  3590.  
  3591. /**
  3592.  * @desc get a string with execution time between "chrono points" and total time spent into "intervals"
  3593.  *
  3594.  * @param boolean $total: set to true to return total script execution time
  3595.  * @return string : XML JS code or plain text result
  3596.  */
  3597. function cfChrono($total=false){
  3598.     if($total) return (microtime(true)-$_ENV['chrono'][0]['time']);
  3599.  
  3600.     cfChronoAddPoint("End");
  3601.     $output='';$sum=0;
  3602.     foreach ($_ENV['chrono'] as $key=>$value) if(isset($_ENV['chrono'][($key)]['time'])) {
  3603.         if($key!=0) $output.=$prevLabel.' <-> '.$value['label'].' : '.cfChronoFormat($_ENV['chrono'][($key)]['time']-$_ENV['chrono'][($key-1)]['time'])."<br>\n";
  3604.         $prevLabel=$value['label'];
  3605.     }
  3606.     $output.=' TOTAL:'.cfChronoFormat($_ENV['chrono'][($key)]['time']-$_ENV['chrono'][0]['time'])."<br>\n\n";
  3607.     if(isset($_ENV['chronoInt']['int'])) foreach ($_ENV['chronoInt']['int'] as $key=>$value) $output.='<br>'.$key.': '.$value['nb'].' x '. cfChronoFormat($value['time']/$value['nb']).' = '.cfChronoFormat($value['time']).' / ';
  3608.  
  3609.     return cfUTF8Encode($output);
  3610. }
  3611.  
  3612. /**
  3613.  * @desc Check if a process is running
  3614.  *
  3615.  * @param mixed $processname : exe name of process (including ".exe"), or PID
  3616.  * @return mixed PID if named process exists, name if PID exists, else return false
  3617.  */
  3618. function cfProcessExists($processname){
  3619.     if(is_integer($processname)){
  3620.         foreach (@win32_ps_list_procs() as $value){if(strtolower(basename($value['pid']))==$processname) return $value['exe'];}
  3621.     }
  3622.     else{
  3623.         $processname=strtolower(str_replace('/','\\',$processname));
  3624.         // Search for process with full path name
  3625.         if(strpos($processname,'\\')!==false)
  3626.             foreach (@win32_ps_list_procs() as $value){if(strtolower($value['exe'])==$processname) return $value['pid'];}
  3627.         // Search for process basename only
  3628.         else
  3629.             foreach (@win32_ps_list_procs() as $value){if(strtolower(basename($value['exe']))==$processname) return $value['pid'];}
  3630.     }
  3631.     return false;
  3632. }
  3633.  
  3634. /**
  3635.  * @desc check if client is a Wii
  3636.  *
  3637.  * @return bool result
  3638.  */
  3639. function cfIsWII(){
  3640.     if(isset($_SERVER['HTTP_USER_AGENT']) && stripos($_SERVER['HTTP_USER_AGENT'], "wii")!==false) return true; else return false;
  3641. }
  3642.  
  3643. /**
  3644.  * @desc Return true if mobile device
  3645.  *
  3646.  * @param $options: 'iPhone' to exclude iPhone/iPod touch, wii to exclude wii
  3647.  * @return boolean
  3648.  */
  3649. function cfIsMobile(){
  3650.     $options=cfArrayValuesToKeys(func_get_args());
  3651.     if(isset($options['iPhone']) && preg_match('/i[Pp]od|i[Pp]hone/',$_SERVER['HTTP_USER_AGENT'])) return false;
  3652.     if(isset($options['wii']) && stripos($_SERVER['HTTP_USER_AGENT'],'wii')) return false;
  3653.     if(isset($options[cfBGetVar('name')])) return false;
  3654.     if(cfBGetVar('type')=='mobile'||cfGGetVar('forceMobile')||isset($_GET['forceMobile'])) return true;
  3655.     return false;
  3656. }
  3657.  
  3658. /**
  3659.  * @desc Tell if this connection processes a resource
  3660.  *
  3661.  * @return bool: true if resource
  3662.  */
  3663. function cfIsResource(){return isset($_ENV['isResource']);/* $_ENV set by security.php */}
  3664.  
  3665. /**
  3666.  * @desc Return true if embeded in application
  3667.  *
  3668.  * @return boolean
  3669.  */
  3670. function cfIsInApp(){
  3671.     static $cache;
  3672.  
  3673.     if(!isset($cache)){
  3674.         $cache=(isset($_ENV['configurationEnvironment']) && $_ENV['configurationEnvironment']=='application') || (cfGGetVar('configurationEnvironment')=='application') || (isset($_GET['weezoKey']) && customCheckKey($_GET['weezoKey'])) || (isset($_SESSION['weezoKey']) && customCheckKey($_SESSION['weezoKey']));
  3675.     }
  3676.     return $cache;
  3677. }
  3678.  
  3679. /**
  3680.  * @desc Return true if CLI
  3681.  *
  3682.  * @return boolean
  3683.  */
  3684. function cfIsCLI(){return !isset($_SERVER['SERVER_NAME']);}
  3685.  
  3686. /**
  3687.  * @desc Return script inclusion code (for a js located in /js dir)
  3688.  *
  3689.  * @param string $script: script name
  3690.  * @return string code
  3691.  */
  3692. function cfScriptLink($script,$embed=false){
  3693.     if($embed||cfBGetVar('inlineJS')) return '<script type="text/javascript">'.file_get_contents(cfAppDocRoot().'/js/'.$script).'</script>'."\n";
  3694.     return '<script src="/js/'.$script.'?v='.cfGGetVar('appVersion').'" type="text/javascript" language="javascript"></script>'."\n";
  3695. }
  3696.  
  3697. /**
  3698.  * @desc use socket to connect, send an HTTP request (using proxy settings) and get result
  3699.  *
  3700.  * @param mixed $URL: array: parsed URL, or string: plain text URL
  3701.  * @param boolean $removeHeader: set to true to remove response's HTTP header, set to false to get full response
  3702.  * @param string $error: error description
  3703.  * @param array $cleanedURL: parsed & cleaned URL
  3704.  * @param integer $maxDataLength: Maximum received data (bytes)
  3705.  * @param boolean $handleOnly: if set to true, data will not be read, and connection not closed. Socket handle is returned
  3706.  * @param boolean $sentHeaders: array of headers to send
  3707.  *                     (key is name, value is content, if value is array, send multiple headers with same name)
  3708.  * @param string $POSTDATA: false for a GET request or encoded POST value for POST requests. Note: Content-Type header must be manualy set
  3709.  * @return mixed: string result (or false if invalid url or socket couldn't be opened), or socket handle if $handleOnly is set to true
  3710.  */
  3711. function cfSocketHTTPRequest($URL, $timeout=7, $removeHeader=true, &$error=false, &$cleanedURL=false, $maxDataLength=false, $handleOnly=false, $sentHeaders=array(), $POSTDATA=false, $downloadCallback=false){
  3712.     if(!is_array($URL)) $cnx=@parse_url($URL); else $cnx=$URL;
  3713.     if(!isset($cnx['host'])) {
  3714.         $error='Invalid URL';
  3715.         return false;
  3716.     }
  3717.     if(!isset($cnx['path'])) $cnx['path']='/';
  3718.  
  3719.     // Set port and scheme
  3720.     if(!isset($cnx['port']) && isset($cnx['scheme']) && $cnx['scheme']=='https') $cnx['port']=443;
  3721.     elseif(!isset($cnx['port'])) $cnx['port']=80;
  3722.     if(!isset($cnx['scheme'])){if($cnx['port']==443) $cnx['scheme']='https'; else $cnx['scheme']='http';}
  3723.     $cleanedURL=$cnx;
  3724.  
  3725.     // Proxy settings
  3726.     $auth_string=false;
  3727.     if($cnx['host']!='localhost' && $cnx['host']!='127.0.0.1' && substr($cnx['host'],0,7)!='192.168' && substr($cnx['host'],0,3)!='10.' && cfGGetVar('proxyEnabled') && cfGGetVar('proxyIP') && cfGGetVar('proxyPort')) { // prod
  3728.         $proxy=true;
  3729.         $host=cfGGetVar('proxyIP');
  3730.         $port=cfGGetVar('proxyPort');
  3731.         if(cfGGetVar('proxyUsername')) $auth_string = "\r\nProxy-authorization: Basic ".base64_encode(cfGGetVar('proxyUsername').':'.cfGGetVar('proxyPassword'));
  3732.     }
  3733.     else {$proxy=false; $host=$cnx['host']; $port=$cnx['port'];}
  3734.  
  3735.     /**
  3736.      * Open socket
  3737.      */
  3738.     if(!($handle = @fsockopen((($cnx['scheme']=='https')?'ssl://':'').$host,$port,$errno,$errstr,$timeout))){$error=$errstr;    return false;}
  3739.  
  3740.     // Send HTTP request
  3741.     $request=(($POSTDATA)?'POST ':'GET ').(($proxy)?$cnx['host'].':'.$cnx['port']:'').$cnx['path'].((isset($cnx['query']))?'?'.$cnx['query']:'')." HTTP/1.0\r\n";
  3742.     $request.="Host: ".$cnx['host'].$auth_string."\r\n";
  3743.     if(is_array($sentHeaders) && count($sentHeaders)) {
  3744.         foreach ($sentHeaders as $key=>$value) if(strtolower($key)!='host') {
  3745.             if(is_array($value)) {foreach ($value as $v) $request.=ucfirst($key).': '.$v."\r\n";}
  3746.             else $request.=ucfirst($key).': '.$value."\r\n";
  3747.         }
  3748.     }
  3749.     else $request.="User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1)\r\n";
  3750.  
  3751.     // POST data
  3752.     if($POSTDATA) $request.="\r\n".$POSTDATA;
  3753.  
  3754.     /**
  3755.      * Send request
  3756.      */
  3757.     @fwrite($handle, $request."\r\n");
  3758.  
  3759.     if($handleOnly) return $handle;
  3760.  
  3761.     // Read response
  3762.     $data='';$totalSize=false;
  3763.     while(!feof($handle) && ((!$maxDataLength) || ($len=strlen($data))<$maxDataLength)) {
  3764.         if($downloadCallback) call_user_func($downloadCallback,$len);
  3765.         $data.=fread($handle, 8192);
  3766.     }
  3767.     fclose($handle);
  3768.  
  3769.     if($maxDataLength) $data=substr($data,0,$maxDataLength-1);
  3770.     if(!$removeHeader) return $data;
  3771.     else return substr($data,strpos($data,"\r\n\r\n")+4);
  3772. }
  3773.  
  3774. /**
  3775.  * @desc Send parallel HTTP requests
  3776.  *
  3777.  * @param mixed $urls: id=>url array or single URL string
  3778.  * @param array $extraOptions: request options (see http://php.net/manual/en/function.curl-setopt.php for description)
  3779.  * @param array redir: array filled with redirected urls (if CURLOPT_FOLLOWLOCATION and CURLOPT_HEADER set)
  3780.  * @return array $id=>$result (or empty array if failed)
  3781.  */
  3782. function cfCURLMultiRequests($urls, $extraOptions = array(),&$redir=array()) {
  3783.     if(!$handle = curl_multi_init()) return array();
  3784.     if(!is_array($urls)) $urls=array('singleURL'=>$urls);
  3785.  
  3786.     // Default options
  3787.     $options=array(CURLOPT_FAILONERROR=>1, CURLOPT_HEADER=>0,CURLOPT_RETURNTRANSFER=>1,CURLOPT_FOLLOWLOCATION=>1,CURLOPT_MAXREDIRS=>3,CURLOPT_FRESH_CONNECT=>1,CURLOPT_TIMEOUT=>7,CURLOPT_SSL_VERIFYHOST => 0,CURLOPT_SSL_VERIFYPEER => false);
  3788.  
  3789.     // Proxy settings
  3790.     if(cfGGetVar('proxyEnabled')) {
  3791.         $options=$options+array(CURLOPT_PROXY=>cfGGetVar('proxyIP'),CURLOPT_PROXYPORT=>cfGGetVar('proxyPort'));
  3792.         if(cfGGetVar('proxyUsername')) $options=$options+array(CURLOPT_PROXYUSERPWD=>cfGGetVar('proxyUsername').':'.cfGGetVar('proxyPassword'));
  3793.     }
  3794.     // Merge with extraOptions
  3795.     $options=$extraOptions+$options;
  3796.     unset($options['callback']);
  3797.  
  3798.     // Add urls
  3799.     $requests = array();
  3800.     foreach ($urls as $id => $url) {
  3801.         $requests[$id] = curl_init($url);
  3802.          curl_setopt_array($requests[$id], $options);
  3803.         curl_multi_add_handle($handle, $requests[$id]);
  3804.     }
  3805.  
  3806.     // Retrieve requests
  3807.     $start=microtime(true); $nb = count($urls); $cycle=0; while($nb>0) {
  3808.         curl_multi_exec($handle,$nb);
  3809.         usleep(50000);
  3810.         if(isset($extraOptions['callback']) && ++$cycle>20) {
  3811.             call_user_func($extraOptions['callback'],$nb,(microtime(true)-$start)/CURLOPT_TIMEOUT);
  3812.             $cycle=0;
  3813.         }
  3814.     }
  3815.  
  3816.     // Get results
  3817.     $results = array();
  3818.     foreach($requests as $id => $response) {
  3819.         $results[$id] = curl_multi_getcontent($response);
  3820.         curl_multi_remove_handle($handle, $response);
  3821.     }
  3822.     curl_multi_close($handle);
  3823.  
  3824.     // Remove redirection headers
  3825.     if($options[CURLOPT_FOLLOWLOCATION] && $options[CURLOPT_HEADER]) foreach ($results as $k=>$v) if($v[9]=="3"){
  3826.         cfParseHTTPResponse($v,$status,$body=null,$headers);
  3827.         if(isset($headers['location'])) {
  3828.             $l=$headers['location'];
  3829.             if(substr($l,0,4)=='http') $redir[$k]=$l;
  3830.         }
  3831.         if(strpos($v,"\r\n\r\n")) $results[$k]=substr($v,strpos($v,"\r\n\r\n")+4);
  3832.         elseif(strpos($v,"\n\r\n\r")) $results[$k]=substr($v,strpos($v,"\n\r\n\r")+4);
  3833.     }
  3834.  
  3835.     // If single URL passed as text string, return as text string
  3836.     if(count($urls)==1 && isset($urls['singleURL'])) return $results['singleURL'];
  3837.     // else return array of results
  3838.     return $results;
  3839. }
  3840.  
  3841. /**
  3842.  * @desc Parse an HTTP response (headers + body)
  3843.  *
  3844.  * @param string $response: HTTP message
  3845.  * @param ingteger $HTTPCode : (return value) HTTP code
  3846.  * @param string $body : (return value), set to 'discard' to discard
  3847.  * @param array $headers : (return value) lowercased HTTP Headers
  3848.  * @return boolean true if message parsed OK, false if not OK
  3849.  */
  3850. function cfParseHTTPResponse($response, &$statusCode, &$body, &$headers, &$fullStatus=null){
  3851.     $headers=array();
  3852.  
  3853.     if(strpos($response,"\r\n")) $sep="\r\n";
  3854.     elseif(strpos($response,"\n\r")) $sep="\n\r";
  3855.     else return false;
  3856.  
  3857.  
  3858.     // Get HTTP status code
  3859.     $resp=substr($response,0,strpos($response,$sep));
  3860.     if($fullStatus!==null) $fullStatus=$resp;
  3861.     $resp=explode(' ',$resp,3);
  3862.     if(count($resp)<2 || !is_numeric($resp[1])) return false;
  3863.     $statusCode=$resp[1];
  3864.  
  3865.     // Separate body and headers
  3866.     $response=substr($response,strpos($response,$sep)+2);
  3867.     $sep.=$sep;
  3868.  
  3869.     // Get body
  3870.     if($body!=='discard'){
  3871.         if(!strpos($response,$sep)) {
  3872.             if(!strpos($response,'<')) return false;
  3873.             $body=substr($response,strpos($response,'<')+1);
  3874.         }
  3875.         else $body=substr($response,strpos($response,$sep)+strlen($sep));
  3876.     }
  3877.  
  3878.     // Parse headers
  3879.     $httpHeaders=explode(substr($sep,0,2),substr($response,0,strpos($response,$sep)));
  3880.     //for($i=0;$i<strlen($response);$i++) echo ' '.$response[$i].':'.ord($response[$i]);
  3881.     foreach ($httpHeaders as $value){
  3882.         if(strpos($value,':')) {
  3883.             $name=strtolower(substr($value,0,strpos($value,':')));
  3884.             // If header is sent multiple times, turn into an array
  3885.             if(isset($headers[$name])){
  3886.                 if(!is_array($headers[$name])) $headers[$name]=array(0=>$headers[$name],1=>trim(substr($value,strpos($value,':')+1)));
  3887.                 else $headers[$name][]=trim(substr($value,strpos($value,':')+1));
  3888.             }
  3889.             // Else just create header
  3890.             else $headers[$name]=trim(substr($value,strpos($value,':')+1));
  3891.         }
  3892.     }
  3893.     return true;
  3894. }
  3895.  
  3896. /**
  3897.  * @desc check if user uses a Weezo.net account
  3898.  *
  3899.  * @return mixed : array : registration info if registered, false if not registered
  3900.  */
  3901. function cfIsRegistered(){
  3902.     $regInfo=cfMGetVar('weezoRegInfo');
  3903.     if(isset($regInfo['regName']) && (!isset($regInfo['noRegistration']) || !$regInfo['noRegistration'])) return $regInfo;
  3904.     else return false;
  3905. }
  3906.  
  3907. /**
  3908.  * Detect browser from user-agent header and store it into weezoBrowser general var
  3909.  *
  3910.  * @return browser's name
  3911.  */
  3912. function cfSetBrowserCaps(){
  3913.     // Get browsers list
  3914.     $browsers=cfMGetVar('weezoBrowsers');
  3915.  
  3916.     if(isset($_GET['HTTP_USER_AGENT'])) $ua=$_GET['HTTP_USER_AGENT']; // Debug
  3917.     elseif(isset($_SERVER['HTTP_USER_AGENT'])) $ua=$_SERVER['HTTP_USER_AGENT'];
  3918.     else{
  3919.         $header=getallheaders();
  3920.         if(isset($header['User-Agent']))  $ua=$header['User-Agent']; else $ua='default';
  3921.     }
  3922.  
  3923.  
  3924.     // Opera mini for iPhone (and maybe other phones): concatenate original phone to user agent
  3925.     if(isset($_SERVER['HTTP_X_OPERAMINI_PHONE_UA'])) $ua.=$_SERVER['HTTP_X_OPERAMINI_PHONE_UA'];
  3926.     $ua=strtolower($ua);
  3927.  
  3928.     // Skyfire browser: no specific signature in UA
  3929.     if(isset($_SERVER['HTTP_X_SKYFIRE_VERSION']) && isset($browsers['Skyfire'])){
  3930.         $caps=$browsers['Skyfire'];
  3931.         $caps['name']='Skyfire';
  3932.         cfGSetVar('browserCaps',$caps);
  3933.     }
  3934.  
  3935.     // search for user-agent signature into "known" browsers (Default browser signature is ".")
  3936.     else foreach ($browsers as $name=>$caps) {
  3937.         if(isset($caps['signature']) && preg_match('/'.strtolower($caps['signature']).'/',$ua)) {
  3938.             // Include name
  3939.             $caps['name']=$name;
  3940.             // Store in general variable
  3941.             cfGSetVar('browserCaps',$caps);
  3942.             break;
  3943.         }
  3944.     }
  3945.  
  3946.     // Apply XHTML theme/scripts if mobile device
  3947.     if($caps['type']=='mobile' && $caps['theme']==false) cfGSetVar('theme','mobile');
  3948.  
  3949.     return $caps['name'];
  3950. }
  3951.  
  3952. /**
  3953.  * @desc display error page
  3954.  *
  3955.  * @param integer $errorCode : HTTP error code
  3956.  */
  3957. function cfHTTPError($errorCode){
  3958.     require_once(INCLUDE_DIR.'outputFunctions.php');
  3959.     cfDebugSingle('HTTP Error '.$errorCode.' sent for '.$_SERVER['REQUEST_URI']);
  3960.  
  3961.     switch ($errorCode){
  3962.         case 403;
  3963.             $message='403 Forbidden';
  3964.             break;
  3965.         case 404:
  3966.         default:
  3967.             $message='404 Not Found';
  3968.             break;
  3969.     }
  3970.     header('HTTP/1.1 '.$message,true,$errorCode);
  3971.  
  3972.     cfLog($message .' - '.$_SERVER["REQUEST_URI"],LOG_DBG);
  3973.     wSession_write_close();
  3974.     outDisplayErrorPage('extAccess - '.$message .' - '.$_SERVER["REQUEST_URI"]);
  3975.     exit();
  3976. }
  3977.  
  3978. /**
  3979.  * @desc Return path to ffmpeg executable
  3980.  *
  3981.  * @return string: complete filename
  3982.  */
  3983. function cfFfmpegExe(){
  3984.     return str_replace('/','\\',cfAppBinDir()).'\\'.((file_exists(cfAppBinDir().'/ffmpeg/weezoFfmpeg.exe'))?'ffmpeg':'ffmpegLGPL').'\\weezoFfmpeg.exe';
  3985. }
  3986.  
  3987. /**
  3988.  * @desc Exec an ffmpeg command line
  3989.  *
  3990.  * @param string $cl: command line
  3991.  */
  3992. function cfFfmpegExec($cl){customExecNoFork(cfFfmpegExe(),'SW_HIDE',$cl);}
  3993.  
  3994. /**
  3995.  * @desc Return ffmpeg version (GPL or LGPL)
  3996.  * @return string: GPL or LGPL
  3997.  */
  3998. function cfFfmpegVersion(){
  3999.     if(file_exists(cfAppBinDir().'/ffmpeg/weezoFfmpeg.exe') && @cfFileSize(cfAppBinDir().'/ffmpeg/weezoFfmpeg.exe')==8156160) return 'GPL'; else return 'LGPL';
  4000. }
  4001.  
  4002. /**
  4003.  * Check if mysql is installed
  4004.  *
  4005.  * @return boolean
  4006.  */
  4007. function cfMySQLInstalled(){return (file_exists(cfAppDataRootDir().'/MySQL/bin/mysqld.exe'));}
  4008.  
  4009. /**
  4010.  * @desc check if client IP matches with an masked ip (using wildcard caracters)
  4011.  *
  4012.  * @param string $maskIP: masked IP
  4013.  * @param string $ip: checked IP
  4014.  * @return boolean result
  4015.  */
  4016. function cfIPMatch($maskIP,$ip=false){
  4017.     if(!$ip) $ip=$_SERVER['REMOTE_ADDR'];
  4018.     $cip=explode('.',$ip);
  4019.     $i=0;
  4020.     foreach (explode('.',$maskIP) as $byte) {
  4021.         if ($byte!='*' && 0+$byte!=0+$cip[$i]) return false;
  4022.         $i++;
  4023.     }
  4024.     return true;
  4025. }
  4026.  
  4027. /**
  4028.  * @desc Verify that remote IP is allowed to log to this account
  4029.  *
  4030.  * @param array $userData: array of user's properties
  4031.  * @param string $ip: checked IP. If not set, use $_SERVER['REMOTE_ADDR']
  4032.  * @return boolean: true if allowed
  4033.  */
  4034. function cfIPFilterCheck($userData,$ip=false){
  4035.     if($ip===false) $ip=$_SERVER['REMOTE_ADDR'];
  4036.  
  4037.     // 1st check against all-users policy
  4038.     if(cfGGetVar('IPFilter') && cfGGetVar('IPFilter')!='no'){
  4039.         if(cfGGetVar('IPFilter')=='include'){
  4040.             if(!($IPFilterIncluded=cfGGetVar('IPFilterIncluded'))) return false;
  4041.             $included=false;
  4042.             foreach (explode(';',$IPFilterIncluded) as $mip) if(cfIPMatch($mip,$ip)){$included=true;break;}
  4043.             if(!$included) return false;
  4044.         }
  4045.         else{
  4046.             if(($IPFilterExcluded=cfGGetVar('IPFilterExcluded'))){
  4047.                 foreach (explode(';',$IPFilterExcluded) as $mip) if(cfIPMatch($mip,$ip)) return false;
  4048.             }
  4049.         }
  4050.     }
  4051.  
  4052.     // Then check user-specific IP policy
  4053.     if(isset($userData['IPFilter']) && $userData['IPFilter']!='no'){
  4054.         if($userData['IPFilter']=='include'){
  4055.             if(!isset($userData['IPFilterIncluded'])) return false;
  4056.             foreach (explode(';',$userData['IPFilterIncluded']) as $mip) if(cfIPMatch($mip,$ip)) return true;
  4057.             return false;
  4058.         }
  4059.         else{
  4060.             if(!isset($userData['IPFilterExcluded'])) return true;
  4061.             foreach (explode(';',$userData['IPFilterExcluded']) as $mip) if(cfIPMatch($mip,$ip)) return false;
  4062.             return true;
  4063.         }
  4064.     }
  4065.     return true;
  4066. }
  4067.  
  4068.  
  4069. /**
  4070.  * @desc Return true if an IP filter applies (global-level and user-level if userData is provided)
  4071.  *
  4072.  * @param array $userData: user config
  4073.  * @return boolean
  4074.  */
  4075. function cfIPFilterIsset($userData=false){
  4076.     if(cfGGetVar('IPFilter') && cfGGetVar('IPFilter')!='no') return true;
  4077.     if(isset($userData['IPFilter']) && $userData['IPFilter']!='no') return true;
  4078.     return false;
  4079. }
  4080.  
  4081. /**
  4082.  * @desc return an array containing session data
  4083.  *
  4084.  * @param string $sessionData : session serialized data
  4085.  * @return array : session data
  4086.  */
  4087. function cfUnserializeSession($sessionData){
  4088.     return unserialize($sessionData);
  4089.     $sess=array();
  4090.     $data = preg_split('/([A-Za-z_][A-Za-z0-9_]*)\|/',$sessionData,-1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
  4091.     for ($i=0;$i<count($data)/2;$i++) $sess[$data[$i*2]]=@unserialize($data[$i*2+1]);
  4092.     return $sess;
  4093. }
  4094.  
  4095. /**
  4096.  * @desc Log user access to a given file, so it can be monitored by admin
  4097.  *
  4098.  * @param string $content: name of accessed content (file name, tv channel name...), not UTF8 encoded
  4099.  */
  4100. function cfLogContentAccess($content){
  4101.     if(!cfGGetVar('historyLogViewedContent')) return ;
  4102.     require_once(INCLUDE_DIR.'databaseFunctions.php');
  4103.     dbLogContentAccess($content);
  4104. }
  4105.  
  4106. /**
  4107.  * @desc Return .lnk target
  4108.  *         http://www.i2s-lab.com/Papers/The_Windows_Shortcut_File_Format.pdf
  4109.  *
  4110.  * @param string $linkCompleteFilename: .lnk file
  4111.  * @return string: target file
  4112.  */
  4113. function cfShortcutResolve($linkCompleteFilename){
  4114.     if(!($fp=fopen($linkCompleteFilename,'rb'))) return false;
  4115.     // Check header
  4116.     $str=fread($fp,4);
  4117.     if($str!="L\0\0\0") {fclose($fp);return false;}
  4118.     fseek($fp,20,SEEK_SET);
  4119.  
  4120.     // Get Flags
  4121.     $flags=unpack('L',fread($fp,4));
  4122.     $flags=str_pad(decbin($flags[1]),'8','0');
  4123.  
  4124.     // Has a shell item IDList
  4125.     if($flags[0]=='1'){
  4126.         fseek($fp,76,SEEK_SET);
  4127.         $shellItemIDListLength=unpack('S',fread($fp,2));
  4128.         $shellItemIDListLength=$shellItemIDListLength[1];
  4129.         $fileLocationInfoPos = 79 + $shellItemIDListLength;
  4130.     }
  4131.     else $fileLocationInfoPos = 79;
  4132.     fseek($fp,$fileLocationInfoPos+15,SEEK_SET);
  4133.     $oBasePath=@unpack('L',fread($fp,4));$oBasePath=isset($oBasePath[1])?$oBasePath[1]:'';
  4134.     /*
  4135.     $oNetwork=unpack('L',fread($fp,4));$oNetwork=$oNetwork[1];
  4136.     $oRemaining=unpack('L',fread($fp,4));$oRemaining=$oRemaining[1];
  4137.     */
  4138.     if($oBasePath){
  4139.         fseek($fp,$fileLocationInfoPos+$oBasePath-1,SEEK_SET);
  4140.         $shortcut='';
  4141.         while(($c=fread($fp,1))!="\0") $shortcut.=$c;
  4142.         fclose($fp);
  4143.         return str_replace('\\','/',$shortcut);
  4144.     }
  4145.     // Try something else...
  4146.     fseek($fp,101,SEEK_SET);
  4147.     $shortcut='';
  4148.     while(!feof($fp) && ($c=fread($fp,1))!="\0") $shortcut.=$c;
  4149.     fclose($fp);
  4150.     if(is_file($shortcut) || is_dir($shortcut)) return str_replace('\\','/',$shortcut);
  4151.     return false;
  4152. }
  4153.  
  4154. /**
  4155.  * @desc load RSA keys if needed (i.e. loginKeyLength!=0)
  4156.  * @return array including key length, private and public exponents, modulo and maxDigits.
  4157.  *             If loginKeyLength is 0, return only keylength
  4158.  *             If error reading keypair, return false
  4159.  *
  4160.  */
  4161. function cfRSALoadKeyPair(){
  4162.     if(!cfGGetVar('loginKeyLength')) return array('keyLength' => 0);
  4163.     // Read file
  4164.     if(!file_exists(cfAppDataDir().'/RSAKey.cnf')){
  4165.         cfLog('login.php: Missing RSAKey.cnf file. Relaunch application to generate file.',LOG_ER);
  4166.         return false;
  4167.     }
  4168.     $kp=parse_ini_file(cfAppDataDir().'/RSAKey.cnf');
  4169.     if(!isset($kp['keyLength']) || !isset($kp['modulo']) || !isset($kp['publicExponent']) || !isset($kp['privateExponent'])){
  4170.         cfLog('login.php: corrupted RSAKey.cnf file. Delete file and relaunch application.',LOG_ER);
  4171.         return false;
  4172.     }
  4173.     // Set maxDigits
  4174.     if($kp['keyLength']<=128) $kp['maxDigits']=19;
  4175.     elseif($kp['keyLength']<=384) $kp['maxDigits']=57;
  4176.     elseif($kp['keyLength']<=512) $kp['maxDigits']=76;
  4177.     elseif($kp['keyLength']<=1024) $kp['maxDigits']=154;
  4178.     else $kp['maxDigits']=308;
  4179.     return $kp;
  4180. }
  4181.  
  4182. /**
  4183.  * @desc Decipher JS RSA encoded string
  4184.  *
  4185.  * @param string $ciphered
  4186.  * @return string
  4187.  */
  4188. function cfRSADecrypt($ciphered,&$wasCiphered=null){
  4189.     require_once 'Crypt/RSA/Math/BCMath.php';
  4190.     require_once 'Crypt/RSA.php';
  4191.  
  4192.     $wasCiphered=false;
  4193.     if(!cfCmpLeft($ciphered,'rsa:')) return $ciphered;
  4194.     $wasCiphered=true; $ciphered=substr($ciphered,4);
  4195.  
  4196.     if(!($RSAKeyPair=cfRSALoadKeyPair())) return false;
  4197.  
  4198.     $dec=new Crypt_RSA();
  4199.     $bcm= new Crypt_RSA_Math_BCMath;
  4200.     $decKey = new Crypt_RSA_Key($bcm->int2bin($RSAKeyPair['modulo']),$bcm->int2bin($RSAKeyPair['privateExponent']),'private');
  4201.  
  4202.     // Decipher returned string
  4203.     $plain='';
  4204.     foreach (explode(';',$ciphered) as $block) {
  4205.         $bytes = split(',', $block);
  4206.         $msg = ''; foreach($bytes as $byte) $msg .= chr((int)$byte);
  4207.         if(strlen($block)>0) $plain.=($dec->alt_decryptBinary($msg,$decKey));
  4208.     }
  4209.     return $plain;
  4210. }
  4211.  
  4212. /**
  4213.  * @desc Generate random ID
  4214.  *
  4215.  * @param integer $lenght
  4216.  * @return string
  4217.  */
  4218. function cfGenerateID($length=16){
  4219.     $id='';
  4220.     for ($i=0;$i<$length;$i++) {
  4221.         $r=rand(0,62);
  4222.         if($r>36) $id.=chr($r+60);
  4223.         elseif($r>10) $id.=chr($r+54);
  4224.         else $id.=$r;
  4225.     }
  4226.     return $id;
  4227. }
  4228.  
  4229. /**
  4230.  * @desc Save modified savable resource var
  4231.  *
  4232.  */
  4233. function cfSetSavedRVarC(){
  4234.     // Search for modified savable vars
  4235.     $mod=false;
  4236.     foreach ($_ENV['savedRVars'] as $k=>$v) if(($nv=cfRGetVar($k))!=$v) $mod[$k]=$nv;
  4237.     if($mod){
  4238.         $saved=@unserialize(WEnv::user()->getVar('savedRVars'));
  4239.         $saved[cfRGetVar('id')]=$mod+$_ENV['savedRVars'];
  4240.         $saved=serialize($saved);
  4241.  
  4242.         // Update session var (will be commited to file at logout)
  4243.         WEnv::user()->setVar('savedRVars',$saved);
  4244.     }
  4245. }
  4246.  
  4247. /**
  4248.  * @desc Manage resource-level variables that will be memorized when user will return
  4249.  *
  4250.  * @param String list of cfRGetVar names, insert 'add' keyword just to add given names to list without comming
  4251.  */
  4252. function cfSetSavedRVar(){
  4253.     // Only single-user accounts may save session vars
  4254.     if(cfUGetVar('accountType')!='singleUser' || !cfIsResource() || cfIsMobile()) return;
  4255.  
  4256.     if(!isset($_ENV['savedRVars'])) $_ENV['savedRVars']=array();
  4257.  
  4258.     $list=array_flip(func_get_args())+$_ENV['savedRVars'];
  4259.     // If 'add' keyword, just add to list and exit
  4260.     if(isset($list['add'])){
  4261.         unset($list['add']);
  4262.         $_ENV['savedRVars']=$list;
  4263.         return;
  4264.     }
  4265.  
  4266.     // 1st resource access: restore saved vars
  4267.     if(!cfRGetVar('savedRVars')){
  4268.         $saved=@unserialize(cfUGetVar('savedRVars'));
  4269.         if(isset($saved[cfRGetVar('id')])){
  4270.             foreach ($saved[cfRGetVar('id')] as $k=>$v) if(isset($list[$k])) cfRSetVar($k,$v);
  4271.         }
  4272.         cfRSetVar('savedRVars',1);
  4273.     }
  4274.     // Memorize initial state vars
  4275.     $saved=@unserialize(cfUGetVar('savedRVars'));
  4276.  
  4277.     if(isset($saved[cfRGetVar('id')])) $_ENV['savedRVars']=$saved[cfRGetVar('id')]; else $_ENV['savedRVars']=array();
  4278.     foreach ($list as $k=>$v) if(!isset($_ENV['savedRVars'][$k])) $_ENV['savedRVars'][$k]=cfRGetVar($k,false,false,null);
  4279.  
  4280.     // Register function that will check at end of script wether vars have been changed or not
  4281.     wSession_setBeforeWriteClose('cfSetSavedRVarC');
  4282. }
  4283.  
  4284. /**
  4285.  * @desc Crypt password with weezoPwdKey for storage
  4286.  *
  4287.  * @param string $pwd
  4288.  * @return string
  4289.  */
  4290. function cfStoredPasswordCrypt($pwd){
  4291.     $key=substr(cfMGetVar('weezoPwdKey'),0,8);
  4292.     $iv =substr(cfMGetVar('weezoPwdKey'),8);
  4293.     return base64_encode(@mcrypt_encrypt(MCRYPT_TRIPLEDES,$key,'PWD'.$pwd.chr(0),MCRYPT_MODE_CBC,$iv));
  4294. }
  4295.  
  4296. /**
  4297.  * Decrypt password encrypted by cfStoredPasswordCrypt
  4298.  *
  4299.  * @param string $pwd
  4300.  * @return string
  4301.  */
  4302. function cfStoredPasswordDecrypt($pwd){
  4303.     $key=substr(cfMGetVar('weezoPwdKey'),0,8);
  4304.     $iv =substr(cfMGetVar('weezoPwdKey'),8);
  4305.     $clear=@mcrypt_decrypt(MCRYPT_TRIPLEDES,$key,base64_decode($pwd),MCRYPT_MODE_CBC,$iv);
  4306.     if(substr($clear,0,3)!=='PWD') return false;
  4307.     return substr($clear,3,strpos($clear,chr(0))-3);
  4308. }
  4309.  
  4310. /**
  4311.  * Return an array of $id=>$WUserConfig, ordered according to general.ini "user" value
  4312.  *
  4313.  * @return array
  4314.  */
  4315. function cfUsersConfigs(){
  4316.     $r=array();
  4317.     $memUsers=cfMGetVar('weezoUsers');
  4318.     foreach (explode(',',cfGGetVar('users')) as $filename){
  4319.         foreach ($memUsers as $id=>$u) {
  4320.             if(isset($u['configFilename']) && $u['configFilename']==$filename){
  4321.                 $uc=new WUserConfig($id,$u);
  4322.                 if($uc->isValid()) $r[$id]=$uc;
  4323.             }
  4324.         }
  4325.     }
  4326.     return $r;
  4327. }
  4328.  
  4329. /**
  4330.  * @desc Return Content Delivery Network prefix URL, or '' if none set.
  4331.  *          This URL must be prefixed before content (gfx and css)
  4332.  *          CDN must be enabled in advanced config.
  4333.  *          CDN is disabled for localhost and for in-app
  4334.  *
  4335.  * @return string
  4336.  */
  4337. function cfCDNPrefix(){
  4338.     static $CDN=-1;
  4339.  
  4340.     // Use Content Delivery Network
  4341.     if($CDN===-1) $CDN=(cfGGetVar('CDN') && cfGGetVar('useCDN')/* && !cfIsInApp() && $_SERVER['REMOTE_ADDR']!=='127.0.0.1'*/ && !isset($_GET['noCDN']))?cfGGetVar('CDN'):'';
  4342.     return $CDN;
  4343. }
  4344.  
  4345.  
  4346. /**
  4347.  * @desc Global env class (in construction)
  4348.  *
  4349.  */
  4350. Class WEnv {
  4351.     static private $config; // Global session environment (general vars)
  4352.     static private $user; // Connected user
  4353.     static private $res; // Active linked resource
  4354.     static private $userConfigs; // Array of users configurations
  4355.     static private $resConfigs; // Array of resources configurations
  4356.     static private $usersLogged; // Array of logged users
  4357.     static private $resLinkedArray; // Array of linked resources
  4358.     static private $session; // Current session data
  4359.  
  4360.     private function __construct() {}
  4361.  
  4362.     /**
  4363.      * @desc Current general config
  4364.      *
  4365.      * @return WConfig
  4366.      */
  4367.     static function config() {
  4368.         if (empty(self::$config))    self::$config = new WConfig();
  4369.         return self::$config;
  4370.     }
  4371.  
  4372.     /**
  4373.      * @desc Current session vars
  4374.      *
  4375.      * @return WSession
  4376.      */
  4377.     static function session() {
  4378.         if (empty(self::$session))    self::$session = new WSession();
  4379.         return self::$session;
  4380.     }
  4381.  
  4382.     /**
  4383.      * @desc Connected user object
  4384.      *
  4385.      * @return WUser
  4386.      */
  4387.     static function user() {
  4388.         if (empty(self::$user))    self::$user = new WUser();
  4389.         return self::$user;
  4390.     }
  4391.  
  4392.     /**
  4393.      * @desc Current resource object
  4394.      *
  4395.      * @return WResLinked
  4396.      */
  4397.     static function res($dataName=false) {
  4398.         if(!empty(self::$res))    return ($dataName)?self::$res->getVar($dataName):self::$res;
  4399.  
  4400.         // If not in app or not logged user, exit
  4401.         if(!cfIsInApp() && !WEnv::user()->isValid()) return false;
  4402.         if(isset($_SESSION['activeResourceId']))
  4403.             self::$res = new WResLinked($_SESSION['res'][$_SESSION['activeResourceId']]['id']);
  4404.         elseif(isset($_ENV['weezoSession']['activeResourceId']))
  4405.             self::$res = new WResLinked($_ENV['weezoSession']['res'][$_ENV['weezoSession']['activeResourceId']]['id']);
  4406.         else return false;
  4407.         return ($dataName)?self::$res->getVar($dataName):self::$res;
  4408.     }
  4409.  
  4410.     /**
  4411.      * @desc Return a linked resource
  4412.      *
  4413.      * @return WResLinked
  4414.      */
  4415.     static function resLinked($id) {
  4416.         if(isset(self::$resLinkedArray[$id])) return self::$resLinkedArray[$id];
  4417.         self::$resLinkedArray[$id]=new WResLinked($id);
  4418.         return self::$resLinkedArray[$id];
  4419.     }
  4420.  
  4421.     /**
  4422.      * @desc return an array of $id=>WConfig of all created resources (except invisible users)
  4423.      *
  4424.      * @return WResConfig array
  4425.      */
  4426.     static function resConfigs(){
  4427.         if (empty(self::$resConfigs))    {
  4428.             self::$resConfigs = array();
  4429.             foreach (cfMGetVar('weezoResourcesList') as $id=>$res) self::$resConfigs[$id]=new WResConfig($id);
  4430.         }
  4431.         return self::$resConfigs;
  4432.     }
  4433.  
  4434.     /**
  4435.      * @desc return an array of $id=>WConfig of all created users (except invisible users), or given user config if id passed
  4436.      * @param $userId (optional): id or config filename of user
  4437.      * @return WUserConfig
  4438.      */
  4439.     static function userConfigs($userId=false){
  4440.         if (empty(self::$userConfigs))    {
  4441.             self::$userConfigs = array();
  4442.             foreach (cfMGetVar('weezoUsers') as $id=>$usr) if(!@$usr['invisible']){
  4443.                 self::$userConfigs[$id]=new WUserConfig($id);
  4444.             }
  4445.         }
  4446.         // Single user requested
  4447.         if($userId) {
  4448.             // Filename
  4449.             if(strpos($userId,'.')){
  4450.                 foreach (self::$userConfigs as $id=>$user) if($user->filename()==$userId) return $user;
  4451.             }
  4452.             // Id
  4453.             return (isset(self::$userConfigs[$id]))?self::$userConfigs[$id]:null;
  4454.         }
  4455.         // Users list
  4456.         return self::$userConfigs;
  4457.     }
  4458.  
  4459.     /**
  4460.      * @desc return an array of $session_id=>$user_config_id of all logged users (except invisible users)
  4461.      *
  4462.      * @return array
  4463.      */
  4464.     static function usersLogged(){
  4465.         if (empty(self::$userLogged))    {
  4466.             self::$usersLogged = array();
  4467.             foreach (cfGlob(cfAppDataDir().'/sessiondata/sess_*') as $cfn){
  4468.                 // Remove application session
  4469.                 if(cfCmpLeft(basename($cfn),'sess_UI')) continue;
  4470.                 $usr=@unserialize(file_get_contents($cfn));
  4471.                 if(@$usr['user']['id'] && $usr['user']['id']!=='standalone') self::$usersLogged[basename($cfn)]=$usr['user']['id'];
  4472.             }
  4473.  
  4474.         }
  4475.         return self::$usersLogged;
  4476.     }
  4477.  
  4478. }
  4479.  
  4480.  
  4481. /**
  4482.  * General configuration
  4483.  *
  4484.  */
  4485. class WConfig{
  4486.     function __construct(){}
  4487.  
  4488.     /**
  4489.      * @desc Retreive config var
  4490.      *
  4491.      * @param string $dataName
  4492.      * @param mixed $dataValue
  4493.      * @param mixed $notFound: value returned if not found
  4494.      * @return mixed
  4495.      */
  4496.     function getVar($dataName=false,$subDataName=false,$notFound=false){
  4497.         if(!$dataName) return (array)@$_ENV['weezoGeneral']+(array)@$_SESSION['weezoGeneral'];
  4498.         if    ($subDataName===false && isset($_SESSION['weezoGeneral'][$dataName])) $data=$_SESSION['weezoGeneral'][$dataName];
  4499.         elseif($subDataName!==false && isset($_SESSION['weezoGeneral'][$dataName][$subDataName])) $data=$_SESSION['weezoGeneral'][$dataName][$subDataName];
  4500.         elseif($subDataName===false && isset($_ENV['weezoGeneral'][$dataName])) $data=$_ENV['weezoGeneral'][$dataName];
  4501.         elseif($subDataName!==false && isset($_ENV['weezoGeneral'][$dataName][$subDataName])) $data=$_ENV['weezoGeneral'][$dataName][$subDataName];
  4502.         else return $notFound;
  4503.         if(!is_array($data) && strtolower($data)=='false') return false;
  4504.         if(!is_array($data) && strtolower($data)=='true') return true;
  4505.         return $data;
  4506.     }
  4507.  
  4508.     /**
  4509.      * @desc Set/update config var for current session
  4510.      *
  4511.      * @param string $dataName
  4512.      * @param mixed $dataValue
  4513.      */
  4514.     function setVar($dataName,$dataValue){cfGSetVar($dataName,$dataValue);}
  4515.  
  4516.     /**
  4517.      * @desc Update/Save config var to general.ini file, and update all necessary stuff
  4518.      *
  4519.      * @param string $dataName
  4520.      * @param mixed $dataValue
  4521.      */
  4522.     function updateVar($dataName,$dataValue){cfGUpdateVar($dataName,$dataValue);}
  4523.  
  4524.     /**
  4525.      * @desc Unset config var
  4526.      *
  4527.      * @param string $dataName: name of data to unset
  4528.      */
  4529.     function unsetVar($dataName){cfGUnsetVar($dataName);}
  4530. }
  4531.  
  4532. /**
  4533.  * @desc Session wrapper. Used to simply access session var, from plugins or genuine weezo scripts. Do not use if perf needed
  4534.  *
  4535.  */
  4536. class WSession{
  4537.     protected $useEnv=false; // True to use $_ENV['weezoSession'], false to use $_SESSION
  4538.     function __construct(){
  4539.         if(isset($_ENV['weezoSession'])) $this->useEnv=true;
  4540.     }
  4541.  
  4542.     /**
  4543.      * @desc Get a session var
  4544.      *
  4545.      * @param string $dataName
  4546.      * @param string $subDataName
  4547.      * @param string $subSubDataName
  4548.      * @return mixed
  4549.      */
  4550.     function getVar($dataName,$subDataName=null,$subSubDataName=null){
  4551.         if($this->useEnv){
  4552.             if(!isset($subDataName)) return @$_ENV['weezoSession'][$dataName];
  4553.             if(!isset($subSubDataName)) return @$_ENV['weezoSession'][$dataName][$subDataName];
  4554.             return @$_ENV['weezoSession'][$dataName][$subDataName][$subSubDataName];
  4555.         }
  4556.         if(!isset($subDataName)) return @$_SESSION[$dataName];
  4557.         if(!isset($subSubDataName)) return @$_SESSION[$dataName][$subDataName];
  4558.         return @$_SESSION[$dataName][$subDataName][$subSubDataName];
  4559.     }
  4560. }
  4561.  
  4562. /**
  4563.  * @desc User configuration class
  4564.  *
  4565.  */
  4566. class WUserConfig{
  4567.     protected $id=0;
  4568.     protected $filename;
  4569.     public $data;
  4570.     protected $modifiedData=false;
  4571.     protected $modifiedName=false;
  4572.     protected $modifiedResources=false; // True if resource(s) added/removed
  4573.     protected $new=false; // True if newly created user
  4574.     protected $valid=false; // True if user successfully loaded
  4575.     protected $invisible=false; // True if user is not a regular logged user (UI, standalone)
  4576.  
  4577.     /**
  4578.      * @desc Constructor
  4579.      *
  4580.      * @param string $id: user unique ID or config filename, or false to create new user
  4581.      */
  4582.     function __construct($id=false,$data=false){
  4583.         if($id==='standalone'){
  4584.             $this->id='standalone';
  4585.             $this->valid=true;
  4586.             $this->invisible=true;
  4587.             return;
  4588.         }
  4589.         if($id&&$data) {
  4590.             if(!isset($data['configFilename'])) return;
  4591.             $this->id=$id;
  4592.             $this->filename=$data['configFilename'];
  4593.             $this->data=$data;
  4594.             $this->valid=true;
  4595.             return true;
  4596.         }
  4597.  
  4598.         $users=cfMGetVar('weezoUsers');
  4599.         // Filename passed
  4600.         if(strpos($id,'.usr')) {
  4601.             $this->filename=$id;
  4602.             foreach ($users as $uid=>$user) if(isset($user['configFilename']) && $user['configFilename']==$this->filename){
  4603.                 $this->id=$uid;
  4604.                 break;
  4605.             }
  4606.             if(!$this->id) return;
  4607.         }
  4608.         // Id passed
  4609.         elseif ($id){
  4610.             if(!isset($users[$id])) return;
  4611.             $this->id=$id;
  4612.             $this->filename=@$users[$id]['configFilename'];
  4613.         }
  4614.         // Nothing passed: user creation
  4615.         else{
  4616.             // Gen ID
  4617.             $this->id=cfGenerateID(10);
  4618.             // Filename
  4619.             $i=0;while(file_exists(cfAppDataDir().'/account'.$i.'.usr')) $i++;
  4620.             $this->filename='account'.$i.'.usr';
  4621.             // Name
  4622.             $nb=0;$found=1;
  4623.             while ($found) {
  4624.                 $nb++;
  4625.                 $found=0;
  4626.                 foreach ($users as $k=>$u) {
  4627.                     if($u['name']==cfUTF8Decode(cfCaption('userDefaultName'))){
  4628.                         $found=1;
  4629.                         break;
  4630.                     }
  4631.                 }
  4632.             }
  4633.             // Other values
  4634.             $this->setVar('name',cfUTF8Decode(cfCaption('userDefaultName')));
  4635.             $this->setVar('icon','default.jpg');
  4636.             $this->setVar('authenticationMethod','noAuthentication');
  4637.             $this->setVar('administrator',false);
  4638.             $this->setVar('hidden',false);
  4639.             $this->setVar('accountType','anonymous');
  4640.             $this->setVar('audioProfile','noSound');
  4641.             $this->setVar('sNotes',1);
  4642.             $this->setVar('configFilename',$this->filename);
  4643.             $this->setVar('activated',true);
  4644.             $this->setVar('id',$this->id);
  4645.             $this->modifiedName=true;
  4646.             $this->modifiedData=true;
  4647.             $this->new=1;
  4648.             $this->valid=true;
  4649.             return;
  4650.         }
  4651.         $this->data=$users[$this->id];
  4652.         $this->valid=true;
  4653.     }
  4654.  
  4655.     /**
  4656.      * @desc User unique ID
  4657.      *
  4658.      * @return string
  4659.      */
  4660.     function id(){return $this->id;}
  4661.  
  4662.     /**
  4663.      * @desc Return user config file name (without path)
  4664.      *
  4665.      * @return string
  4666.      */
  4667.     function filename(){return $this->filename;}
  4668.  
  4669.     /**
  4670.      * @desc Return true if user config exists
  4671.      *
  4672.      * @return bool
  4673.      */
  4674.     function isValid(){return $this->valid;}
  4675.  
  4676.  
  4677.     /**
  4678.      * Get all configuration data
  4679.      *
  4680.      * @return arrat
  4681.      */
  4682.     function getData(){return $this->data;}
  4683.  
  4684.     /**
  4685.      * @desc Get a var
  4686.      *
  4687.      * @param string $dataName
  4688.      * @return mixed
  4689.      */
  4690.     function getVar($dataName){return @$this->data[$dataName];}
  4691.  
  4692.     /**
  4693.      * @desc Set/update a var. Must use save() to commit to file/memory
  4694.      *
  4695.      * @param string $dataName
  4696.      * @param mixed $value
  4697.      */
  4698.     function setVar($dataName,$value){
  4699.         if(!isset($this->data[$dataName]) || $this->data[$dataName]!=$value) {
  4700.             $this->modifiedData=true;
  4701.             if($dataName=='name') $this->modifiedName=true;
  4702.         }
  4703.         $this->data[$dataName]=$value;
  4704.     }
  4705.  
  4706.     /**
  4707.      * @desc Get user definition
  4708.      *
  4709.      * @param string $dataName
  4710.      * @return mixed
  4711.      */
  4712.     function getDefinition($dataName=false){
  4713.         if(!$dataName) return @$this->data['definition'];
  4714.         return @$this->data['definition'][$dataName];
  4715.     }
  4716.  
  4717.     /**
  4718.      * @desc Return true if use is invisible (technical account)
  4719.      *
  4720.      * @return bool
  4721.      */
  4722.     function isInvisible(){return @$this->data['invisible'];}
  4723.  
  4724.     /**
  4725.      * @desc Return true if user is administrator
  4726.      *
  4727.      * @return bool
  4728.      */
  4729.     function isAdministrator(){return @$this->data['administrator'];}
  4730.  
  4731.     /**
  4732.      * @desc Return an array of id=>resourceFilename or $id=>WResConfig
  4733.      *
  4734.      * @param bool: $returnObjects: true to return WResConfig instead of filenames
  4735.      * @return array
  4736.      */
  4737.     function getResources($returnObjects=false){
  4738.         $ret=array();
  4739.         $res=cfArraySwapKeysValues(cfMGetVar('weezoResourcesList'));
  4740.  
  4741.         // Browse user's resources
  4742.         for($i=0;true;$i++){
  4743.             if(!isset($this->data['resource'.$i])) return $ret;
  4744.             $file=$this->data['resource'.$i]['file'];
  4745.             if(isset($res[$file])) {
  4746.                 $rid=$res[$file];
  4747.                 if($returnObjects)
  4748.                     $ret[$rid]=new WResConfig($rid);
  4749.                 else
  4750.                     $ret[$rid]=$file;
  4751.             }
  4752.         }
  4753.         return $ret;
  4754.     }
  4755.  
  4756.     /**
  4757.      * @desc Return an array of resources linked to user
  4758.      *
  4759.      * @return array of id=>resourceFilename or $id=>WResLinked
  4760.      */
  4761.     function getResourcesLinked(){
  4762.         $ret=array();
  4763.         $res=cfArraySwapKeysValues(cfMGetVar('weezoResourcesList'));
  4764.  
  4765.         // Browse user's resources
  4766.         for($i=0;true;$i++){
  4767.             if(!isset($this->data['resource'.$i])) return $ret;
  4768.             $file=$this->data['resource'.$i]['file'];
  4769.             if(isset($res[$file])) {
  4770.                 $rid=$res[$file];
  4771.                 $ret[$rid]=new WResLinked($rid);
  4772.             }
  4773.         }
  4774.         return $ret;
  4775.     }
  4776.  
  4777.     /**
  4778.      * @desc Swap 2 bound resources
  4779.      *
  4780.      * @param $r1: id of 1st res
  4781.      * @param $r2: id of 2nd res
  4782.      */
  4783.     function swapResources($r1,$r2){
  4784.         $res=array();
  4785.         $prev=cfArraySwapKeysValues($this->getResources());
  4786.         $prevD=array();
  4787.         for($i=0;true;$i++){
  4788.             if(!isset($this->data['resource'.$i])) break;
  4789.             $prevD[$prev[$this->data['resource'.$i]['file']]]=$this->data['resource'.$i];
  4790.         }
  4791.         $i=0;
  4792.         foreach ($prevD as $rid=>$r){
  4793.             if($rid==$r1) $this->setVar('resource'.$i,$prevD[$r2]);
  4794.             elseif($rid==$r2) $this->setVar('resource'.$i,$prevD[$r1]);
  4795.             else $this->setVar('resource'.$i,$r);
  4796.             $i++;
  4797.         }
  4798.  
  4799.         $this->modifiedData=true;
  4800.         $this->modifiedResources=true;
  4801.     }
  4802.  
  4803.     /**
  4804.      * @desc Remove resource
  4805.      *
  4806.      * @param string $filename: resource config filename or id
  4807.      */
  4808.     function removeResource($filename){
  4809.         // If not a filename, convert to id
  4810.         if(!strpos($filename,'.res') && !($filename=cfArrayItem(cfMGetVar('weezoResData'.$filename),'resourceFilename'))) return;
  4811.         $found=0;
  4812.         for($i=0;true;$i++){
  4813.             if(!isset($this->data['resource'.$i])) break;
  4814.             $file=$this->data['resource'.$i]['file'];
  4815.             if($found) {
  4816.                 $this->data['resource'.($i-1)]=$this->data['resource'.$i];
  4817.                 unset($this->data['resource'.$i]);
  4818.             }
  4819.             if(!$found && $file==$filename){
  4820.                 unset($this->data['resource'.$i]);
  4821.                 $found=1;
  4822.             }
  4823.         }
  4824.         if($found) {
  4825.             $this->modifiedData=true;
  4826.             $this->modifiedResources=true;
  4827.         }
  4828.     }
  4829.  
  4830.     /**
  4831.      * @desc Add a resource
  4832.      *
  4833.      * @param string $rid: resource id
  4834.      */
  4835.     function addResource($rid){
  4836.         if(!($res=cfMGetVar('weezoResData'.$rid))) return;
  4837.         $i=0;while ($this->getVar('resource'.(int)$i)) $i++;
  4838.         $this->setVar('resource'.(int)$i,array('file'=>$res['resourceFilename'],'type'=>$res['type'],'subType'=>$res['subType']));
  4839.         $this->modifiedData=true;
  4840.         $this->modifiedResources=true;
  4841.     }
  4842.  
  4843.     /**
  4844.      * @desc Update a resource
  4845.      *
  4846.      * @param string $rid
  4847.      * @param string $dataName
  4848.      * @param mixed $dataValue
  4849.      */
  4850.     function updateResource($rid,$dataName,$dataValue,$fromWUser=false){
  4851.         if(!($res=cfMGetVar('weezoResData'.$rid))) return;
  4852.         if(!($resourceFilename=cfArrayItem(cfMGetVar('weezoResourcesList'),$rid))) return;
  4853.         $i=0;
  4854.         while ($ures=$this->getVar('resource'.(int)$i)) {
  4855.             if(@$ures['file']==$resourceFilename){
  4856.                 if(@$ures[$dataName]!==$dataValue){
  4857.                     $ures[$dataName]=$dataValue;
  4858.                     // Update var
  4859.                     $this->setVar('resource'.(int)$i,$ures);
  4860.  
  4861.                     // If resource update is called from WUser object, apply to WUserConfig object
  4862.                     if($fromWUser) $this->saveVar('resource'.(int)$i,$ures);
  4863.                 }
  4864.                 return ;
  4865.             }
  4866.             $i++;
  4867.         }
  4868.     }
  4869.  
  4870.     // Commit changes to file
  4871.     function save(){
  4872.         // Don't save if not modified
  4873.         if(!$this->modifiedData) return ;
  4874.  
  4875.         // Save to file
  4876.         cfWriteIniFile($this->data,cfAppDataDir().'/'.$this->filename);
  4877.  
  4878.         // Update in-memory data
  4879.         $users=cfMGetVar('weezoUsers');
  4880.         $users[$this->id]=$this->data;
  4881.         cfMSetVar('weezoUsers',$users);
  4882.  
  4883.         // Update database
  4884.         if($this->modifiedName) {
  4885.             require_once('databaseFunctions.php');
  4886.             $db=sqlite_open(cfAppDataDir().'/cnxStats.db');
  4887.             $query="INSERT INTO account VALUES ('".$this->id()."' ,'".$this->getVar('name')."','".(int)($this->isAdministrator())."','".time()."')";
  4888.             @sqlite_query($query, $db);
  4889.             $query="UPDATE account SET name='".$this->getVar('name')."' WHERE id='".$this->id()."'";
  4890.             sqlite_query($query, $db);
  4891.             sqlite_close($db);
  4892.         }
  4893.         // Update opened sessions
  4894.         if($this->modifiedResources){
  4895.             require_once(INCLUDE_DIR.'initFunctions.php');
  4896.             ifResetResourcesUsers();
  4897.         }
  4898.  
  4899.         // New user: add to users list in general.ini
  4900.         if($this->new)    cfGUpdateVar('users',cfGGetVar('users').','.$this->filename,true);
  4901.  
  4902.         // Update in-app display
  4903.         if(!cfIsInApp()) cfServerSendCmd('refreshUsers');
  4904.  
  4905.         $this->modifiedResources=false;
  4906.         $this->modifiedData=false;
  4907.         $this->modifiedName=false;
  4908.         $this->new=false;
  4909.     }
  4910.  
  4911.     // Destroy user
  4912.     function del(){
  4913.         // Remove config file
  4914.         @unlink($this->data,cfAppDataDir().'/'.$this->filename);
  4915.  
  4916.         // Update general.ini
  4917.         $u=array();
  4918.         foreach (explode(',',cfGGetVar('users')) as $ufn) if($ufn!=$this->filename) $u[]=$ufn;
  4919.         cfGUpdateVar('users',implode(',',$u));
  4920.  
  4921.         // Remove in-memory user
  4922.         $u=cfMGetVar('weezoUsers');
  4923.         unset($u[$this->id]);
  4924.         cfMSetVar('weezoUsers',$u);
  4925.  
  4926.         // Inform app
  4927.         cfServerSendCmd('userDeleted',array('file'=>$this->filename));
  4928.     }
  4929. }
  4930.  
  4931. /**
  4932.  * @desc Currently connected user. Accessed through WEnv
  4933.  *
  4934.  */
  4935. class WUser extends WUserConfig {
  4936.     protected $valid=true;
  4937.  
  4938.     function __construct(){
  4939.         // Construct from session (plugins)
  4940.         if(isset($_ENV['weezoSession']['user']['id'])) parent::__construct($_ENV['weezoSession']['user']['id']);
  4941.         // Construct from session
  4942.         elseif(isset($_SESSION['user']['id'])) parent::__construct($_SESSION['user']['id']);
  4943.         // Not logged
  4944.         else $this->valid=false;
  4945.     }
  4946.  
  4947.     /**
  4948.      * @desc Return true if user is logged
  4949.      *
  4950.      * @return bool
  4951.      */
  4952.     function isLogged(){
  4953.         return isset($_SESSION['userLogged']) && $this->valid;
  4954.     }
  4955.  
  4956.     /**
  4957.      * @desc Get var
  4958.      *
  4959.      * @param string $dataName
  4960.      * @return mixed
  4961.      */
  4962.     function getVar($dataName){
  4963.         // Session-level (plugins)
  4964.         if(isset($_ENV['weezoSession']['user'][$dataName])) return $_ENV['weezoSession']['user'][$dataName];
  4965.         // Session-level
  4966.         if(isset($_SESSION['user'][$dataName])) return $_SESSION['user'][$dataName];
  4967.         // User-config level
  4968.         return @$this->data[$dataName];
  4969.     }
  4970.  
  4971.     /**
  4972.      * @desc Set/update for this session
  4973.      *
  4974.      * @param string $dataName: name of data to save
  4975.      * @param mixed $dataValue
  4976.      */
  4977.     function setVar($dataName,$dataValue){
  4978.         // Save for this session
  4979.         $_SESSION['user'][$dataName]=$dataValue;
  4980.     }
  4981.  
  4982.     /**
  4983.      * @desc Update/save to file a given data
  4984.      *
  4985.      * @param string $dataName: name of data to save
  4986.      * @param bool $commit: true to save now, false to wait for a call to save()
  4987.      */
  4988.     function saveVar($dataName,$commit=true){
  4989.         parent::setVar($dataName,$this->getVar($dataName));
  4990.         if($commit) parent::save();
  4991.     }
  4992.  
  4993.     function updateResource($rid,$dataName,$dataValue){
  4994.         parent::updateResource($rid,$dataName,$dataValue,true);
  4995.     }
  4996. }
  4997.  
  4998.  
  4999. /**
  5000.  * @desc Resource definition class
  5001.  *
  5002.  */
  5003. class WResDefinition{
  5004.     protected $data;
  5005.     protected $type;
  5006.     protected $subType;
  5007.  
  5008.     /**
  5009.      * @desc Constructor
  5010.      *
  5011.      * @param string $type
  5012.      * @param string $subType
  5013.      */
  5014.     function __construct($type,$subType){
  5015.         $this->data=cfMGetVar('weezoResourceDefinition'.strtolower($type).strtolower($subType));
  5016.         $this->type=$type;
  5017.         $this->subType=$subType;
  5018.     }
  5019.  
  5020.     /**
  5021.      * @desc Return true if resource definition successfully loaded
  5022.      *
  5023.      * @return bool
  5024.      */
  5025.     function isValid(){
  5026.         if($this->data) return true; else return false;
  5027.     }
  5028.  
  5029.     /**
  5030.      * @desc Return resource's data
  5031.      *
  5032.      * @param string $dataName: name of data
  5033.      * @return mixed data value
  5034.      */
  5035.     function getVar($dataName=false){
  5036.         if(!$dataName) return $this->data;
  5037.         return @$this->data[$dataName];
  5038.     }
  5039.  
  5040.     /**
  5041.      * @desc Return resource's describer or describer item
  5042.      *
  5043.      * @param string $dataName: name of describer's data. If omitted, return whole describer
  5044.      * @param string $subDataName: name of describer's data
  5045.      * @return mixed describer or data value
  5046.      */
  5047.     function getDescriber($dataName=false,$subDataName=false){
  5048.         if($dataName && $subDataName) return @$this->data['describer'][$dataName][$subDataName];
  5049.         if($dataName) return @$this->data['describer'][$dataName];
  5050.         return $this->data['describer'];
  5051.     }
  5052.  
  5053.     /**
  5054.      * @desc Return 16x16 icon URI
  5055.      *
  5056.      * @return string: path to icon from document root
  5057.      */
  5058.     function icon16(){return $this->data['resourceIconSmall'];}
  5059.  
  5060.     /**
  5061.      * @desc Return 16x16 icon URI
  5062.      *
  5063.      * @return string: path to icon from document root
  5064.      */    function icon32(){return $this->data['resourceIcon'];}
  5065.  
  5066.     /**
  5067.      * @desc Return preview URI
  5068.      *
  5069.      * @return string: path to preview image from document root
  5070.      */    function previewImage(){return $this->data['resourcePreviewImage'];}
  5071.  
  5072.     /**
  5073.      * @desc Return resource's label, in user's language
  5074.      *
  5075.      * @return string
  5076.      */
  5077.     function label(){
  5078.         if(cfCaptionExist(strtolower($this->type).'_'.strtolower($this->subType).'-name')) return cfCaption(strtolower($this->type).'_'.strtolower($this->subType).'-name');
  5079.         $lng=WEnv::config()->getVar((cfIsInApp())?'languageUI':'language');
  5080.         if($label=$this->getDescriber($lng,'name')) return $label;
  5081.         if($label=$this->getDescriber('en','name')) return $label;
  5082.         return $this->subType;
  5083.     }
  5084.  
  5085.     /**
  5086.      * @desc Return resource's description, in user's language
  5087.      *
  5088.      * @return string
  5089.      */
  5090.     function description(){
  5091.         if(cfCaptionExist(strtolower($this->type).'_'.strtolower($this->subType).'-description')) return cfCaption(strtolower($this->type).'_'.strtolower($this->subType).'-description');
  5092.         $lng=WEnv::config()->getVar((cfIsInApp())?'languageUI':'language');
  5093.         if($label=$this->getDescriber($lng,'description')) return $label;
  5094.         if($label=$this->getDescriber('en','description')) return $label;
  5095.         return $this->subType;
  5096.     }
  5097. }
  5098.  
  5099. /**
  5100.  * @desc Configured resource class
  5101.  *
  5102.  */
  5103. class WResConfig {
  5104.     protected $data; // Resource config data
  5105.     protected $modified=false; // True if any modified
  5106.     protected $def; // WResDefinition
  5107.     protected $dataDir;
  5108.  
  5109.     /**
  5110.      * @desc Constructor
  5111.      *
  5112.      * @param string $idOrFilename: resource id or config filename (use false to make false object, used for IDE autocompletition)
  5113.      */
  5114.     function __construct($idOrFilename=false){
  5115.         if(!$idOrFilename) return ;
  5116.         // Treat $idOrFilename as id
  5117.         $this->data=cfMGetVar('weezoResData'.$idOrFilename);
  5118.         if(!$this->data){
  5119.             // If not found,try as filename
  5120.             if(!cfCmpRight($idOrFilename,'.res')) return;
  5121.             if($id=cfArrayItem(cfArraySwapKeysValues(cfMGetVar('weezoResourcesList')),$idOrFilename))
  5122.                 $this->data=cfMGetVar('weezoResData'.$id);
  5123.         }
  5124.  
  5125.         $this->def=new WResDefinition($this->getVar('type'),$this->getVar('subType'));
  5126.     }
  5127.  
  5128.     /**
  5129.      * @desc Cast object to string
  5130.      *
  5131.      * @return string
  5132.      */
  5133.     function __toString() {
  5134.         if(!$this->data) return 'invalid WResConfig';
  5135.         return "WResConfig Object:\nid=".@$this->data['id']."\nname=".@$this->data['name']."\nfilename=".@$this->data['resourceFilename']."\ns/st=".@$this->data['type'].'/'.$this->data['type'];
  5136.     }
  5137.  
  5138.  
  5139.     /**
  5140.      * @desc Return true if resource config successfully loaded
  5141.      *
  5142.      * @return bool
  5143.      */
  5144.     function isValid(){if($this->data) return true; return false;}
  5145.  
  5146.     /**
  5147.      * @desc Return configuration filename
  5148.      *
  5149.      * @return string
  5150.      */
  5151.     function filename(){return $this->getVar('resourceFilename');}
  5152.  
  5153.     /**
  5154.      * @desc Return resource's data
  5155.      *
  5156.      * @param string $dataName: name of data
  5157.      * @return mixed data value
  5158.      */
  5159.     function getVar($dataName=false){
  5160.         if(!$dataName) return $this->data;
  5161.         if(isset($this->data[$dataName])) return $this->data[$dataName];
  5162.         return $this->def->getVar($dataName);
  5163.     }
  5164.  
  5165.     /**
  5166.      * @desc Return resource's data
  5167.      *
  5168.      * @param string $dataName: name of data
  5169.      * @return mixed data value
  5170.      */
  5171.     function setVar($dataName, $dataValue){
  5172.         if($dataName=='id' || $dataName=='filename') return ;
  5173.         if(@$this->data[$dataName]===$dataValue) return ;
  5174.         $this->$modified=true;
  5175.         $this->data[$dataName]=$dataValue;
  5176.     }
  5177.  
  5178.     /**
  5179.      * @desc Return resource id
  5180.      *
  5181.      * @return string
  5182.      */
  5183.     function id(){return $this->getVar('id');}
  5184.  
  5185.     /**
  5186.      * @desc Return resource name
  5187.      *
  5188.      * @return string
  5189.      */
  5190.     function name(){return $this->getVar('name');}
  5191.  
  5192.     /**
  5193.      * @desc Return resource's definition (or resource's definition item if dataName passed)
  5194.      *
  5195.      * @param string $dataName
  5196.      * @return WResDefinition
  5197.      */
  5198.     function definition($dataName=false){
  5199.         if($dataName) return $this->def->getVar($dataName);
  5200.         return $this->def;
  5201.     }
  5202.  
  5203.     /**
  5204.      * @desc Return resource's data directory (/data/res/{type}/{subtype}/{config_filename_without_extension)
  5205.      *
  5206.      * @return string
  5207.      */
  5208.     function dataDir(){
  5209.         // Cached result
  5210.         if(isset($this->dataDir)) return $this->dataDir;
  5211.         $this->dataDir=cfAppDataDir().'/res/'.$this->getVar('type').'/'.$this->getVar('subType').'/'.cfFileWithoutExtension($this->filename());
  5212.         // Try to create resource directory if needed
  5213.         if(!is_dir($this->dataDir)) @mkdir($this->dataDir);
  5214.         return $this->dataDir;
  5215.     }
  5216.  
  5217.     function icon16(){return $this->def->icon16();}
  5218.     function icon32(){return $this->def->icon32();}
  5219. }
  5220.  
  5221. /**
  5222.  * @desc Return a linked resource (object) to currently logged user
  5223.  *
  5224.  */
  5225. class WResLinked{
  5226.     protected $id; // Resource id
  5227.     protected $nid; // Resource numeric id (sequential id in session)
  5228.     protected $isActive ; // True if linked resource is active resource
  5229.     protected $data; // Linked resource data (from session), set only if resource is not active resource
  5230.     protected $config; // Resource config object
  5231.     protected $valid=true;
  5232.  
  5233.     /**
  5234.      * @desc Direct access to getVar
  5235.      *
  5236.      * @param string $dataName
  5237.      * @return mixed
  5238.      */
  5239.     function __invoke($dataName){
  5240.         return cfRGetVar($dataName,false,false,null);
  5241.     }
  5242.  
  5243.     /**
  5244.      * @desc Creator
  5245.      *
  5246.      * @param string $rid: id of linked resource
  5247.      */
  5248.     function __construct($rid=false){
  5249.         if(!$rid){
  5250.             $nid=((isset($_SESSION['activeResourceId']))?$_SESSION['activeResourceId']:((isset($_ENV['weezoSession']['activeResourceId']))?$_ENV['weezoSession']['activeResourceId']:false));
  5251.             if(!$nid) return;
  5252.             $this->id=$rid;
  5253.             $this->nid=$nid;
  5254.             $this->isActive=true;
  5255.             return;
  5256.         }
  5257.         else{
  5258.             foreach (WEnv::session()->getVar('res') as $nid=>$resArr) if($resArr['id']===$rid){
  5259.                 $this->id=$rid;
  5260.                 $this->nid=$nid;
  5261.                 $this->isActive=false;
  5262.                 $this->data=WEnv::session()->getVar('res',$nid);
  5263.                 return;
  5264.             }
  5265.         }
  5266.         $this->valid=false;
  5267.     }
  5268.  
  5269.     /**
  5270.      * @desc Return resource's data
  5271.      *
  5272.      * @param string $dataName: name of data
  5273.      * @return mixed data value
  5274.      */
  5275.     function getVar($dataName){
  5276.         if(!$this->valid) return null;
  5277.         if($this->isActive) return cfRGetVar($dataName,false,false,null);
  5278.         return isset($this->data[$dataName])?$this->data[$dataName]:$this->config()->getVar($dataName);
  5279.     }
  5280.  
  5281.     /**
  5282.      * @desc Return resource's data
  5283.      *
  5284.      * @param string $dataName: name of data
  5285.      * @return mixed data value
  5286.      */
  5287.     function setVar($dataName, $dataValue){
  5288.         if($dataName=='id' || $dataName=='filename') return ;
  5289.         if($this->isActive) cfRSetVar($dataName,$dataValue);
  5290.         else{
  5291.             // Save to object
  5292.             $this->data['dataName']=$dataValue;
  5293.             // Save to session
  5294.             $_SESSION['res'][$this->nid]['dataName']=$dataValue;
  5295.         }
  5296.     }
  5297.  
  5298.     /**
  5299.      * @desc Return resource's config object
  5300.      *
  5301.      * @return WResConfig
  5302.      */
  5303.     function config(){
  5304.  
  5305.         if(!isset($this->config)) $this->config=new WResConfig($this->id);
  5306.         return $this->config;
  5307.     }
  5308.  
  5309.     function __toString(){return $this->config()->__toString();}
  5310. }
  5311.  
  5312. /**
  5313.  * @desc HTTP outgoing headers
  5314.  *
  5315.  */
  5316. class WHeaders{
  5317.     /**
  5318.      * @desc Send no-cache headers
  5319.      *
  5320.      */
  5321.     static function noCache(){
  5322.         header('Expires: '.gmdate("D, d M Y H:i:s",0).' GMT');
  5323.         header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
  5324.         header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
  5325.         header("Pragma: no-cache");
  5326.     }
  5327.  
  5328.     /**
  5329.      * @desc Send cache headers
  5330.      *
  5331.      * @param string $completeFilename: if set, use file mtime for last modification date
  5332.      */
  5333.     static function cache($completeFilename=false){
  5334.         if($completeFilename) header('Last-Modified: '.gmdate("D, d M Y H:i:s",@filemtime($completeFilename)).' GMT');
  5335.         header('Expires: '.gmdate("D, d M Y H:i:s",time()+3600*24*100).' GMT');
  5336.         header('Pragma:');
  5337.         header('Cache-Control: private');
  5338.         header('Etag: "'.md5($_SERVER['REQUEST_URI']).'"');
  5339.     }
  5340.  
  5341.     /**
  5342.      * @desc Send content-type header
  5343.      *
  5344.      * @param string $completeFilename
  5345.      */
  5346.     static function contentType($completeFilename){
  5347.         str_replace('/','/',$completeFilename,$c);
  5348.         // If completeFilename is the mime type
  5349.         if($c==1 && !strpos($completeFilename,'.'))
  5350.             header('Content-Type: "'.$completeFilename);
  5351.         // Actual filename
  5352.         else{
  5353.             require_once(INCLUDE_DIR.'explorerFunctions.php');
  5354.             header('Content-Type: '.efFileMimeType($completeFilename));
  5355.         }
  5356.     }
  5357. }
  5358. ?>